From b21307932d9c287cf40928351bdb93cb855c2dbe Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Fri, 16 Jan 2015 13:46:18 +0100 Subject: [PATCH] libbpg-0.9.3 --- ChangeLog | 30 + Makefile | 190 + README | 174 + VERSION | 1 + bpgdec.c | 350 + bpgenc.c | 2312 +++++++ bpgenc.h | 61 + config.h | 1832 ++++++ doc/bpg_spec.txt | 426 ++ html/bpgdec.js | 91 + html/bpgdec8b.js | 91 + html/index.html | 30 + html/lena512color.bpg | Bin 0 -> 15148 bytes jctvc/Makefile | 54 + jctvc/TAppEncCfg.cpp | 2405 +++++++ jctvc/TAppEncCfg.h | 374 ++ jctvc/TAppEncTop.cpp | 695 ++ jctvc/TAppEncTop.h | 103 + jctvc/TLibCommon/AccessUnit.h | 76 + jctvc/TLibCommon/CommonDef.h | 299 + jctvc/TLibCommon/ContextModel.cpp | 129 + jctvc/TLibCommon/ContextModel.h | 108 + jctvc/TLibCommon/ContextModel3DBuffer.cpp | 120 + jctvc/TLibCommon/ContextModel3DBuffer.h | 98 + jctvc/TLibCommon/ContextTables.h | 502 ++ jctvc/TLibCommon/Debug.cpp | 449 ++ jctvc/TLibCommon/Debug.h | 266 + jctvc/TLibCommon/NAL.h | 118 + jctvc/TLibCommon/SEI.cpp | 126 + jctvc/TLibCommon/SEI.h | 591 ++ jctvc/TLibCommon/TComBitCounter.h | 71 + jctvc/TLibCommon/TComBitStream.cpp | 390 ++ jctvc/TLibCommon/TComBitStream.h | 228 + jctvc/TLibCommon/TComCABACTables.cpp | 123 + jctvc/TLibCommon/TComCABACTables.h | 61 + jctvc/TLibCommon/TComChromaFormat.cpp | 142 + jctvc/TLibCommon/TComChromaFormat.h | 277 + jctvc/TLibCommon/TComCodingStatistics.h | 470 ++ jctvc/TLibCommon/TComDataCU.cpp | 3354 ++++++++++ jctvc/TLibCommon/TComDataCU.h | 570 ++ jctvc/TLibCommon/TComInterpolationFilter.cpp | 383 ++ jctvc/TLibCommon/TComInterpolationFilter.h | 81 + jctvc/TLibCommon/TComList.h | 115 + jctvc/TLibCommon/TComLoopFilter.cpp | 923 +++ jctvc/TLibCommon/TComLoopFilter.h | 143 + jctvc/TLibCommon/TComMotionInfo.cpp | 351 + jctvc/TLibCommon/TComMotionInfo.h | 160 + jctvc/TLibCommon/TComMv.h | 156 + jctvc/TLibCommon/TComPattern.cpp | 734 +++ jctvc/TLibCommon/TComPattern.h | 114 + jctvc/TLibCommon/TComPic.cpp | 177 + jctvc/TLibCommon/TComPic.h | 181 + jctvc/TLibCommon/TComPicSym.cpp | 483 ++ jctvc/TLibCommon/TComPicSym.h | 162 + jctvc/TLibCommon/TComPicYuv.cpp | 257 + jctvc/TLibCommon/TComPicYuv.h | 166 + jctvc/TLibCommon/TComPicYuvMD5.cpp | 222 + jctvc/TLibCommon/TComPrediction.cpp | 841 +++ jctvc/TLibCommon/TComPrediction.h | 143 + jctvc/TLibCommon/TComRdCost.cpp | 1606 +++++ jctvc/TLibCommon/TComRdCost.h | 230 + .../TLibCommon/TComRdCostWeightPrediction.cpp | 489 ++ jctvc/TLibCommon/TComRdCostWeightPrediction.h | 64 + jctvc/TLibCommon/TComRectangle.h | 50 + jctvc/TLibCommon/TComRom.cpp | 675 ++ jctvc/TLibCommon/TComRom.h | 237 + jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp | 724 ++ jctvc/TLibCommon/TComSampleAdaptiveOffset.h | 106 + jctvc/TLibCommon/TComSlice.cpp | 2417 +++++++ jctvc/TLibCommon/TComSlice.h | 1595 +++++ jctvc/TLibCommon/TComTU.cpp | 254 + jctvc/TLibCommon/TComTU.h | 167 + jctvc/TLibCommon/TComTrQuant.cpp | 3333 ++++++++++ jctvc/TLibCommon/TComTrQuant.h | 328 + jctvc/TLibCommon/TComWeightPrediction.cpp | 376 ++ jctvc/TLibCommon/TComWeightPrediction.h | 101 + jctvc/TLibCommon/TComYuv.cpp | 426 ++ jctvc/TLibCommon/TComYuv.h | 207 + jctvc/TLibCommon/TypeDef.h | 826 +++ jctvc/TLibEncoder/AnnexBwrite.h | 91 + jctvc/TLibEncoder/NALwrite.cpp | 123 + jctvc/TLibEncoder/NALwrite.h | 88 + jctvc/TLibEncoder/SEIwrite.cpp | 791 +++ jctvc/TLibEncoder/SEIwrite.h | 84 + jctvc/TLibEncoder/SyntaxElementWriter.cpp | 132 + jctvc/TLibEncoder/SyntaxElementWriter.h | 97 + jctvc/TLibEncoder/TEncAnalyze.cpp | 54 + jctvc/TLibEncoder/TEncAnalyze.h | 366 ++ jctvc/TLibEncoder/TEncBinCoder.h | 83 + jctvc/TLibEncoder/TEncBinCoderCABAC.cpp | 440 ++ jctvc/TLibEncoder/TEncBinCoderCABAC.h | 108 + .../TLibEncoder/TEncBinCoderCABACCounter.cpp | 139 + jctvc/TLibEncoder/TEncBinCoderCABACCounter.h | 74 + jctvc/TLibEncoder/TEncCavlc.cpp | 1508 +++++ jctvc/TLibEncoder/TEncCavlc.h | 144 + jctvc/TLibEncoder/TEncCfg.h | 879 +++ jctvc/TLibEncoder/TEncCu.cpp | 1649 +++++ jctvc/TLibEncoder/TEncCu.h | 177 + jctvc/TLibEncoder/TEncEntropy.cpp | 741 +++ jctvc/TLibEncoder/TEncEntropy.h | 193 + jctvc/TLibEncoder/TEncGOP.cpp | 2837 ++++++++ jctvc/TLibEncoder/TEncGOP.h | 193 + jctvc/TLibEncoder/TEncPic.cpp | 156 + jctvc/TLibEncoder/TEncPic.h | 115 + jctvc/TLibEncoder/TEncPreanalyzer.cpp | 141 + jctvc/TLibEncoder/TEncPreanalyzer.h | 62 + jctvc/TLibEncoder/TEncRateCtrl.cpp | 1402 ++++ jctvc/TLibEncoder/TEncRateCtrl.h | 335 + .../TLibEncoder/TEncSampleAdaptiveOffset.cpp | 1362 ++++ jctvc/TLibEncoder/TEncSampleAdaptiveOffset.h | 168 + jctvc/TLibEncoder/TEncSbac.cpp | 2008 ++++++ jctvc/TLibEncoder/TEncSbac.h | 221 + jctvc/TLibEncoder/TEncSearch.cpp | 5814 +++++++++++++++++ jctvc/TLibEncoder/TEncSearch.h | 474 ++ jctvc/TLibEncoder/TEncSlice.cpp | 1224 ++++ jctvc/TLibEncoder/TEncSlice.h | 136 + jctvc/TLibEncoder/TEncTop.cpp | 1056 +++ jctvc/TLibEncoder/TEncTop.h | 183 + jctvc/TLibEncoder/WeightPredAnalysis.cpp | 386 ++ jctvc/TLibEncoder/WeightPredAnalysis.h | 82 + jctvc/TLibVideoIO/TVideoIOYuv.cpp | 988 +++ jctvc/TLibVideoIO/TVideoIOYuv.h | 86 + jctvc/encmain.cpp | 110 + jctvc/encoder_intra_main.cfg | 103 + jctvc/libmd5/MD5.h | 75 + jctvc/libmd5/libmd5.c | 256 + jctvc/libmd5/libmd5.h | 58 + jctvc/program_options_lite.cpp | 498 ++ jctvc/program_options_lite.h | 237 + jctvc_glue.cpp | 189 + libavcodec/allcodecs.c | 592 ++ libavcodec/avcodec.h | 5246 +++++++++++++++ libavcodec/bit_depth_template.c | 98 + libavcodec/bswapdsp.h | 32 + libavcodec/bytestream.h | 374 ++ libavcodec/cabac.c | 227 + libavcodec/cabac.h | 62 + libavcodec/cabac_functions.h | 198 + libavcodec/cabac_tablegen.h | 108 + libavcodec/get_bits.h | 707 ++ libavcodec/golomb.c | 285 + libavcodec/golomb.h | 623 ++ libavcodec/hevc.c | 3623 ++++++++++ libavcodec/hevc.h | 1075 +++ libavcodec/hevc_cabac.c | 1601 +++++ libavcodec/hevc_filter.c | 917 +++ libavcodec/hevc_mvs.c | 777 +++ libavcodec/hevc_parser.c | 350 + libavcodec/hevc_ps.c | 1701 +++++ libavcodec/hevc_refs.c | 551 ++ libavcodec/hevc_sei.c | 211 + libavcodec/hevcdsp.c | 340 + libavcodec/hevcdsp.h | 144 + libavcodec/hevcdsp_template.c | 1744 +++++ libavcodec/hevcpred.c | 104 + libavcodec/hevcpred.h | 46 + libavcodec/hevcpred_template.c | 620 ++ libavcodec/internal.h | 267 + libavcodec/mathops.h | 230 + libavcodec/old_codec_ids.h | 397 ++ libavcodec/put_bits.h | 258 + libavcodec/rnd_avg.h | 51 + libavcodec/thread.h | 143 + libavcodec/utils.c | 369 ++ libavcodec/version.h | 188 + libavcodec/videodsp.h | 87 + libavutil/adler32.h | 55 + libavutil/aes.h | 65 + libavutil/atomic.h | 79 + libavutil/atomic_gcc.h | 78 + libavutil/atomic_suncc.h | 55 + libavutil/atomic_win32.h | 53 + libavutil/attributes.h | 160 + libavutil/audio_fifo.h | 153 + libavutil/audioconvert.h | 6 + libavutil/avassert.h | 66 + libavutil/avconfig.h | 7 + libavutil/avstring.h | 371 ++ libavutil/avutil.h | 344 + libavutil/base64.h | 67 + libavutil/blowfish.h | 77 + libavutil/bprint.h | 216 + libavutil/bswap.h | 109 + libavutil/buffer.c | 358 + libavutil/buffer.h | 274 + libavutil/buffer_internal.h | 94 + libavutil/cast5.h | 67 + libavutil/channel_layout.h | 222 + libavutil/colorspace.h | 111 + libavutil/common.h | 469 ++ libavutil/cpu.h | 116 + libavutil/cpu_internal.h | 34 + libavutil/crc.h | 86 + libavutil/des.h | 61 + libavutil/dict.h | 178 + libavutil/display.h | 86 + libavutil/downmix_info.h | 115 + libavutil/dynarray.h | 70 + libavutil/error.h | 126 + libavutil/eval.h | 113 + libavutil/ffversion.h | 4 + libavutil/fifo.h | 158 + libavutil/file.h | 66 + libavutil/fixed_dsp.h | 144 + libavutil/float_dsp.h | 188 + libavutil/frame.c | 661 ++ libavutil/frame.h | 703 ++ libavutil/hash.h | 112 + libavutil/hmac.h | 99 + libavutil/imgutils.h | 213 + libavutil/integer.h | 86 + libavutil/internal.h | 269 + libavutil/intfloat.h | 77 + libavutil/intmath.h | 178 + libavutil/intreadwrite.h | 629 ++ libavutil/lfg.h | 62 + libavutil/libm.h | 189 + libavutil/lls.h | 64 + libavutil/log.h | 353 + libavutil/log2_tab.c | 32 + libavutil/lzo.h | 66 + libavutil/macros.h | 48 + libavutil/mathematics.h | 164 + libavutil/md5.c | 236 + libavutil/md5.h | 81 + libavutil/mem.c | 571 ++ libavutil/mem.h | 379 ++ libavutil/motion_vector.h | 50 + libavutil/murmur3.h | 32 + libavutil/old_pix_fmts.h | 177 + libavutil/opencl.h | 298 + libavutil/opencl_internal.h | 33 + libavutil/opt.h | 897 +++ libavutil/parseutils.h | 187 + libavutil/pca.h | 35 + libavutil/pixdesc.c | 170 + libavutil/pixdesc.h | 385 ++ libavutil/pixelutils.h | 52 + libavutil/pixfmt.h | 521 ++ libavutil/qsort.h | 117 + libavutil/random_seed.h | 43 + libavutil/rational.h | 166 + libavutil/rc4.h | 50 + libavutil/replaygain.h | 51 + libavutil/ripemd.h | 75 + libavutil/samplefmt.h | 271 + libavutil/sha.h | 74 + libavutil/sha512.h | 75 + libavutil/softfloat.h | 132 + libavutil/stereo3d.h | 152 + libavutil/threadmessage.h | 91 + libavutil/time.h | 56 + libavutil/time_internal.h | 47 + libavutil/timecode.h | 140 + libavutil/timer.h | 90 + libavutil/timestamp.h | 78 + libavutil/tree.h | 132 + libavutil/version.h | 137 + libavutil/x86_cpu.h | 1 + libavutil/xga_font_data.h | 35 + libavutil/xtea.h | 64 + libbpg.c | 1560 +++++ libbpg.h | 123 + post.js | 168 + tmalloc.c | 314 + x265_glue.c | 166 + 266 files changed, 108670 insertions(+) create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 README create mode 100644 VERSION create mode 100644 bpgdec.c create mode 100644 bpgenc.c create mode 100644 bpgenc.h create mode 100644 config.h create mode 100644 doc/bpg_spec.txt create mode 100644 html/bpgdec.js create mode 100644 html/bpgdec8b.js create mode 100644 html/index.html create mode 100644 html/lena512color.bpg create mode 100644 jctvc/Makefile create mode 100644 jctvc/TAppEncCfg.cpp create mode 100644 jctvc/TAppEncCfg.h create mode 100644 jctvc/TAppEncTop.cpp create mode 100644 jctvc/TAppEncTop.h create mode 100644 jctvc/TLibCommon/AccessUnit.h create mode 100644 jctvc/TLibCommon/CommonDef.h create mode 100644 jctvc/TLibCommon/ContextModel.cpp create mode 100644 jctvc/TLibCommon/ContextModel.h create mode 100644 jctvc/TLibCommon/ContextModel3DBuffer.cpp create mode 100644 jctvc/TLibCommon/ContextModel3DBuffer.h create mode 100644 jctvc/TLibCommon/ContextTables.h create mode 100644 jctvc/TLibCommon/Debug.cpp create mode 100644 jctvc/TLibCommon/Debug.h create mode 100644 jctvc/TLibCommon/NAL.h create mode 100644 jctvc/TLibCommon/SEI.cpp create mode 100644 jctvc/TLibCommon/SEI.h create mode 100644 jctvc/TLibCommon/TComBitCounter.h create mode 100644 jctvc/TLibCommon/TComBitStream.cpp create mode 100644 jctvc/TLibCommon/TComBitStream.h create mode 100644 jctvc/TLibCommon/TComCABACTables.cpp create mode 100644 jctvc/TLibCommon/TComCABACTables.h create mode 100644 jctvc/TLibCommon/TComChromaFormat.cpp create mode 100644 jctvc/TLibCommon/TComChromaFormat.h create mode 100644 jctvc/TLibCommon/TComCodingStatistics.h create mode 100644 jctvc/TLibCommon/TComDataCU.cpp create mode 100644 jctvc/TLibCommon/TComDataCU.h create mode 100644 jctvc/TLibCommon/TComInterpolationFilter.cpp create mode 100644 jctvc/TLibCommon/TComInterpolationFilter.h create mode 100644 jctvc/TLibCommon/TComList.h create mode 100644 jctvc/TLibCommon/TComLoopFilter.cpp create mode 100644 jctvc/TLibCommon/TComLoopFilter.h create mode 100644 jctvc/TLibCommon/TComMotionInfo.cpp create mode 100644 jctvc/TLibCommon/TComMotionInfo.h create mode 100644 jctvc/TLibCommon/TComMv.h create mode 100644 jctvc/TLibCommon/TComPattern.cpp create mode 100644 jctvc/TLibCommon/TComPattern.h create mode 100644 jctvc/TLibCommon/TComPic.cpp create mode 100644 jctvc/TLibCommon/TComPic.h create mode 100644 jctvc/TLibCommon/TComPicSym.cpp create mode 100644 jctvc/TLibCommon/TComPicSym.h create mode 100644 jctvc/TLibCommon/TComPicYuv.cpp create mode 100644 jctvc/TLibCommon/TComPicYuv.h create mode 100644 jctvc/TLibCommon/TComPicYuvMD5.cpp create mode 100644 jctvc/TLibCommon/TComPrediction.cpp create mode 100644 jctvc/TLibCommon/TComPrediction.h create mode 100644 jctvc/TLibCommon/TComRdCost.cpp create mode 100644 jctvc/TLibCommon/TComRdCost.h create mode 100644 jctvc/TLibCommon/TComRdCostWeightPrediction.cpp create mode 100644 jctvc/TLibCommon/TComRdCostWeightPrediction.h create mode 100644 jctvc/TLibCommon/TComRectangle.h create mode 100644 jctvc/TLibCommon/TComRom.cpp create mode 100644 jctvc/TLibCommon/TComRom.h create mode 100644 jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp create mode 100644 jctvc/TLibCommon/TComSampleAdaptiveOffset.h create mode 100644 jctvc/TLibCommon/TComSlice.cpp create mode 100644 jctvc/TLibCommon/TComSlice.h create mode 100644 jctvc/TLibCommon/TComTU.cpp create mode 100644 jctvc/TLibCommon/TComTU.h create mode 100644 jctvc/TLibCommon/TComTrQuant.cpp create mode 100644 jctvc/TLibCommon/TComTrQuant.h create mode 100644 jctvc/TLibCommon/TComWeightPrediction.cpp create mode 100644 jctvc/TLibCommon/TComWeightPrediction.h create mode 100644 jctvc/TLibCommon/TComYuv.cpp create mode 100644 jctvc/TLibCommon/TComYuv.h create mode 100644 jctvc/TLibCommon/TypeDef.h create mode 100644 jctvc/TLibEncoder/AnnexBwrite.h create mode 100644 jctvc/TLibEncoder/NALwrite.cpp create mode 100644 jctvc/TLibEncoder/NALwrite.h create mode 100644 jctvc/TLibEncoder/SEIwrite.cpp create mode 100644 jctvc/TLibEncoder/SEIwrite.h create mode 100644 jctvc/TLibEncoder/SyntaxElementWriter.cpp create mode 100644 jctvc/TLibEncoder/SyntaxElementWriter.h create mode 100644 jctvc/TLibEncoder/TEncAnalyze.cpp create mode 100644 jctvc/TLibEncoder/TEncAnalyze.h create mode 100644 jctvc/TLibEncoder/TEncBinCoder.h create mode 100644 jctvc/TLibEncoder/TEncBinCoderCABAC.cpp create mode 100644 jctvc/TLibEncoder/TEncBinCoderCABAC.h create mode 100644 jctvc/TLibEncoder/TEncBinCoderCABACCounter.cpp create mode 100644 jctvc/TLibEncoder/TEncBinCoderCABACCounter.h create mode 100644 jctvc/TLibEncoder/TEncCavlc.cpp create mode 100644 jctvc/TLibEncoder/TEncCavlc.h create mode 100644 jctvc/TLibEncoder/TEncCfg.h create mode 100644 jctvc/TLibEncoder/TEncCu.cpp create mode 100644 jctvc/TLibEncoder/TEncCu.h create mode 100644 jctvc/TLibEncoder/TEncEntropy.cpp create mode 100644 jctvc/TLibEncoder/TEncEntropy.h create mode 100644 jctvc/TLibEncoder/TEncGOP.cpp create mode 100644 jctvc/TLibEncoder/TEncGOP.h create mode 100644 jctvc/TLibEncoder/TEncPic.cpp create mode 100644 jctvc/TLibEncoder/TEncPic.h create mode 100644 jctvc/TLibEncoder/TEncPreanalyzer.cpp create mode 100644 jctvc/TLibEncoder/TEncPreanalyzer.h create mode 100644 jctvc/TLibEncoder/TEncRateCtrl.cpp create mode 100644 jctvc/TLibEncoder/TEncRateCtrl.h create mode 100644 jctvc/TLibEncoder/TEncSampleAdaptiveOffset.cpp create mode 100644 jctvc/TLibEncoder/TEncSampleAdaptiveOffset.h create mode 100644 jctvc/TLibEncoder/TEncSbac.cpp create mode 100644 jctvc/TLibEncoder/TEncSbac.h create mode 100644 jctvc/TLibEncoder/TEncSearch.cpp create mode 100644 jctvc/TLibEncoder/TEncSearch.h create mode 100644 jctvc/TLibEncoder/TEncSlice.cpp create mode 100644 jctvc/TLibEncoder/TEncSlice.h create mode 100644 jctvc/TLibEncoder/TEncTop.cpp create mode 100644 jctvc/TLibEncoder/TEncTop.h create mode 100644 jctvc/TLibEncoder/WeightPredAnalysis.cpp create mode 100644 jctvc/TLibEncoder/WeightPredAnalysis.h create mode 100644 jctvc/TLibVideoIO/TVideoIOYuv.cpp create mode 100644 jctvc/TLibVideoIO/TVideoIOYuv.h create mode 100644 jctvc/encmain.cpp create mode 100644 jctvc/encoder_intra_main.cfg create mode 100644 jctvc/libmd5/MD5.h create mode 100644 jctvc/libmd5/libmd5.c create mode 100644 jctvc/libmd5/libmd5.h create mode 100644 jctvc/program_options_lite.cpp create mode 100644 jctvc/program_options_lite.h create mode 100644 jctvc_glue.cpp create mode 100644 libavcodec/allcodecs.c create mode 100644 libavcodec/avcodec.h create mode 100644 libavcodec/bit_depth_template.c create mode 100644 libavcodec/bswapdsp.h create mode 100644 libavcodec/bytestream.h create mode 100644 libavcodec/cabac.c create mode 100644 libavcodec/cabac.h create mode 100644 libavcodec/cabac_functions.h create mode 100644 libavcodec/cabac_tablegen.h create mode 100644 libavcodec/get_bits.h create mode 100644 libavcodec/golomb.c create mode 100644 libavcodec/golomb.h create mode 100644 libavcodec/hevc.c create mode 100644 libavcodec/hevc.h create mode 100644 libavcodec/hevc_cabac.c create mode 100644 libavcodec/hevc_filter.c create mode 100644 libavcodec/hevc_mvs.c create mode 100644 libavcodec/hevc_parser.c create mode 100644 libavcodec/hevc_ps.c create mode 100644 libavcodec/hevc_refs.c create mode 100644 libavcodec/hevc_sei.c create mode 100644 libavcodec/hevcdsp.c create mode 100644 libavcodec/hevcdsp.h create mode 100644 libavcodec/hevcdsp_template.c create mode 100644 libavcodec/hevcpred.c create mode 100644 libavcodec/hevcpred.h create mode 100644 libavcodec/hevcpred_template.c create mode 100644 libavcodec/internal.h create mode 100644 libavcodec/mathops.h create mode 100644 libavcodec/old_codec_ids.h create mode 100644 libavcodec/put_bits.h create mode 100644 libavcodec/rnd_avg.h create mode 100644 libavcodec/thread.h create mode 100644 libavcodec/utils.c create mode 100644 libavcodec/version.h create mode 100644 libavcodec/videodsp.h create mode 100644 libavutil/adler32.h create mode 100644 libavutil/aes.h create mode 100644 libavutil/atomic.h create mode 100644 libavutil/atomic_gcc.h create mode 100644 libavutil/atomic_suncc.h create mode 100644 libavutil/atomic_win32.h create mode 100644 libavutil/attributes.h create mode 100644 libavutil/audio_fifo.h create mode 100644 libavutil/audioconvert.h create mode 100644 libavutil/avassert.h create mode 100644 libavutil/avconfig.h create mode 100644 libavutil/avstring.h create mode 100644 libavutil/avutil.h create mode 100644 libavutil/base64.h create mode 100644 libavutil/blowfish.h create mode 100644 libavutil/bprint.h create mode 100644 libavutil/bswap.h create mode 100644 libavutil/buffer.c create mode 100644 libavutil/buffer.h create mode 100644 libavutil/buffer_internal.h create mode 100644 libavutil/cast5.h create mode 100644 libavutil/channel_layout.h create mode 100644 libavutil/colorspace.h create mode 100644 libavutil/common.h create mode 100644 libavutil/cpu.h create mode 100644 libavutil/cpu_internal.h create mode 100644 libavutil/crc.h create mode 100644 libavutil/des.h create mode 100644 libavutil/dict.h create mode 100644 libavutil/display.h create mode 100644 libavutil/downmix_info.h create mode 100644 libavutil/dynarray.h create mode 100644 libavutil/error.h create mode 100644 libavutil/eval.h create mode 100644 libavutil/ffversion.h create mode 100644 libavutil/fifo.h create mode 100644 libavutil/file.h create mode 100644 libavutil/fixed_dsp.h create mode 100644 libavutil/float_dsp.h create mode 100644 libavutil/frame.c create mode 100644 libavutil/frame.h create mode 100644 libavutil/hash.h create mode 100644 libavutil/hmac.h create mode 100644 libavutil/imgutils.h create mode 100644 libavutil/integer.h create mode 100644 libavutil/internal.h create mode 100644 libavutil/intfloat.h create mode 100644 libavutil/intmath.h create mode 100644 libavutil/intreadwrite.h create mode 100644 libavutil/lfg.h create mode 100644 libavutil/libm.h create mode 100644 libavutil/lls.h create mode 100644 libavutil/log.h create mode 100644 libavutil/log2_tab.c create mode 100644 libavutil/lzo.h create mode 100644 libavutil/macros.h create mode 100644 libavutil/mathematics.h create mode 100644 libavutil/md5.c create mode 100644 libavutil/md5.h create mode 100644 libavutil/mem.c create mode 100644 libavutil/mem.h create mode 100644 libavutil/motion_vector.h create mode 100644 libavutil/murmur3.h create mode 100644 libavutil/old_pix_fmts.h create mode 100644 libavutil/opencl.h create mode 100644 libavutil/opencl_internal.h create mode 100644 libavutil/opt.h create mode 100644 libavutil/parseutils.h create mode 100644 libavutil/pca.h create mode 100644 libavutil/pixdesc.c create mode 100644 libavutil/pixdesc.h create mode 100644 libavutil/pixelutils.h create mode 100644 libavutil/pixfmt.h create mode 100644 libavutil/qsort.h create mode 100644 libavutil/random_seed.h create mode 100644 libavutil/rational.h create mode 100644 libavutil/rc4.h create mode 100644 libavutil/replaygain.h create mode 100644 libavutil/ripemd.h create mode 100644 libavutil/samplefmt.h create mode 100644 libavutil/sha.h create mode 100644 libavutil/sha512.h create mode 100644 libavutil/softfloat.h create mode 100644 libavutil/stereo3d.h create mode 100644 libavutil/threadmessage.h create mode 100644 libavutil/time.h create mode 100644 libavutil/time_internal.h create mode 100644 libavutil/timecode.h create mode 100644 libavutil/timer.h create mode 100644 libavutil/timestamp.h create mode 100644 libavutil/tree.h create mode 100644 libavutil/version.h create mode 100644 libavutil/x86_cpu.h create mode 100644 libavutil/xga_font_data.h create mode 100644 libavutil/xtea.h create mode 100644 libbpg.c create mode 100644 libbpg.h create mode 100644 post.js create mode 100644 tmalloc.c create mode 100644 x265_glue.c diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..1a8ae53 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,30 @@ +version 0.9.3: + +- Fixed small palette PNG. +- Added support for BT 709 and BT 2020 YCbCr. +- Added limited range color support. +- Changed CMYK signalling. +- Added premultiplied alpha support. +- Specified the output RGB color space if no color profile is present. +- Reduced the size of the js decoder. +- Removed buffer overflows. + +version 0.9.2: + +- Fixed encoding of paletted PNG. +- Reduced memory usage in the decoder. +- Added faster 8 bit only Javascript decoder. +- bpgenc: added '-e' option to explicitely select the encoder. +- bpgenc: set default bit depth to 8. +- bpgenc: added lossless support with x265. +- js decoder: handle width and height attributes. + +version 0.9.1: + +- Added new meta data tags: ICC profile, XMP and thumbnail. +- Disabled metadata copying by default. +- Use same chroma pixel position as JPEG for 4:2:2 and 4:2:0. + +version 0.9: + +- Initial release. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..db068cf --- /dev/null +++ b/Makefile @@ -0,0 +1,190 @@ +# libbpg Makefile +# +# Compile options: +# +# Enable compilation of Javascript decoder with Emscripten +#USE_EMCC=y +# Enable x265 for the encoder (you must install it before) +#USE_X265=y +# Enable the JCTVC code (best quality but slow) for the encoder +USE_JCTVC=y +# Enable it to use bit depths > 12 (need more tests to validate encoder) +#USE_JCTVC_HIGH_BIT_DEPTH=y +# Enable the cross compilation for Windows +#CONFIG_WIN32=y +# Enable for compilation on MacOS X +#CONFIG_APPLE=y +# Installation prefix +prefix=/usr/local + + +################################# + +ifdef CONFIG_WIN32 +#CROSS_PREFIX:=x86_64-w64-mingw32- +CROSS_PREFIX=i686-w64-mingw32- +EXE:=.exe +else +CROSS_PREFIX:= +EXE:= +endif + +CC=$(CROSS_PREFIX)gcc +CXX=$(CROSS_PREFIX)g++ +AR=$(CROSS_PREFIX)ar +EMCC=emcc + +PWD:=$(shell pwd) + +CFLAGS:=-Os -Wall -MMD -fno-asynchronous-unwind-tables -fdata-sections -ffunction-sections -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -fomit-frame-pointer +CFLAGS+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_REENTRANT +CFLAGS+=-I. +CFLAGS+=-DCONFIG_BPG_VERSION=\"$(shell cat VERSION)\" +ifdef USE_JCTVC_HIGH_BIT_DEPTH +CFLAGS+=-DRExt__HIGH_BIT_DEPTH_SUPPORT +endif + +# Emscriptem config +EMLDFLAGS:=-s "EXPORTED_FUNCTIONS=['_bpg_decoder_open','_bpg_decoder_decode','_bpg_decoder_get_info','_bpg_decoder_start','_bpg_decoder_get_line','_bpg_decoder_close','_malloc','_free']" +EMLDFLAGS+=-s NO_FILESYSTEM=1 -s NO_BROWSER=1 +#EMLDFLAGS+=-O1 --post-js post.js +EMLDFLAGS+=-O3 --memory-init-file 0 --closure 1 --post-js post.js +EMCFLAGS:=$(CFLAGS) + +LDFLAGS=-g +ifdef CONFIG_APPLE +LDFLAGS+=-Wl,-dead_strip +else +LDFLAGS+=-Wl,--gc-sections +endif +CFLAGS+=-g +CXXFLAGS=$(CFLAGS) + +PROGS=bpgdec$(EXE) bpgenc$(EXE) +ifdef USE_EMCC +PROGS+=bpgdec.js bpgdec8b.js +endif + +all: $(PROGS) + +LIBBPG_OBJS:=$(addprefix libavcodec/, \ +hevc_cabac.o hevc_filter.o hevc.o hevcpred.o hevc_refs.o\ +hevcdsp.o hevc_mvs.o hevc_ps.o hevc_sei.o\ +utils.o cabac.o golomb.o ) +LIBBPG_OBJS+=$(addprefix libavutil/, mem.o buffer.o log2_tab.o frame.o pixdesc.o md5.o ) +LIBBPG_OBJS+=libbpg.o + +LIBBPG_JS_OBJS:=$(patsubst %.o, %.js.o, $(LIBBPG_OBJS)) tmalloc.js.o + +LIBBPG_JS8_OBJS:=$(patsubst %.o, %.js8.o, $(LIBBPG_OBJS)) tmalloc.js8.o + +$(LIBBPG_OBJS): CFLAGS+=-D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DHAVE_AV_CONFIG_H -std=c99 -D_GNU_SOURCE=1 -DUSE_VAR_BIT_DEPTH + +$(LIBBPG_JS_OBJS): EMCFLAGS+=-D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DHAVE_AV_CONFIG_H -std=c99 -D_GNU_SOURCE=1 -DUSE_VAR_BIT_DEPTH + +$(LIBBPG_JS8_OBJS): EMCFLAGS+=-D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DHAVE_AV_CONFIG_H -std=c99 -D_GNU_SOURCE=1 + +BPGENC_OBJS:=bpgenc.o +BPGENC_LIBS:= + +ifdef USE_X265 +BPGENC_OBJS+=x265_glue.o +BPGENC_LIBS+= -lx265 +bpgenc.o: CFLAGS+=-DUSE_X265 +endif # USE_X265 + +ifdef USE_JCTVC +JCTVC_OBJS=$(addprefix jctvc/TLibEncoder/, SyntaxElementWriter.o TEncSbac.o \ +TEncBinCoderCABACCounter.o TEncGOP.o\ +TEncSampleAdaptiveOffset.o TEncBinCoderCABAC.o TEncAnalyze.o\ +TEncEntropy.o TEncTop.o SEIwrite.o TEncPic.o TEncRateCtrl.o\ +WeightPredAnalysis.o TEncSlice.o TEncCu.o NALwrite.o TEncCavlc.o\ +TEncSearch.o TEncPreanalyzer.o) +JCTVC_OBJS+=jctvc/TLibVideoIO/TVideoIOYuv.o +JCTVC_OBJS+=$(addprefix jctvc/TLibCommon/, TComWeightPrediction.o TComLoopFilter.o\ +TComBitStream.o TComMotionInfo.o TComSlice.o ContextModel3DBuffer.o\ +TComPic.o TComRdCostWeightPrediction.o TComTU.o TComPicSym.o\ +TComPicYuv.o TComYuv.o TComTrQuant.o TComInterpolationFilter.o\ +ContextModel.o TComSampleAdaptiveOffset.o SEI.o TComPrediction.o\ +TComDataCU.o TComChromaFormat.o Debug.o TComRom.o\ +TComPicYuvMD5.o TComRdCost.o TComPattern.o TComCABACTables.o) +JCTVC_OBJS+=jctvc/libmd5/libmd5.o +JCTVC_OBJS+=jctvc/TAppEncCfg.o jctvc/TAppEncTop.o jctvc/program_options_lite.o + +$(JCTVC_OBJS) jctvc_glue.o: CFLAGS+=-I$(PWD)/jctvc -Wno-sign-compare + +jctvc/libjctvc.a: $(JCTVC_OBJS) + $(AR) rcs $@ $^ + +BPGENC_OBJS+=jctvc_glue.o jctvc/libjctvc.a + +bpgenc.o: CFLAGS+=-DUSE_JCTVC +endif # USE_JCTVC + +ifdef CONFIG_WIN32 +LIBS:=-lz +LDFLAGS+=-static +else +ifdef CONFIG_APPLE +LIBS:= +else +LIBS:=-lrt +endif # !CONFIG_APPLE +LIBS+=-lm -lpthread +endif # !CONFIG_WIN32 + +BPGENC_LIBS+=-lpng -ljpeg $(LIBS) + +bpgenc.o: CFLAGS+=-Wno-unused-but-set-variable + +libbpg.a: $(LIBBPG_OBJS) + $(AR) rcs $@ $^ + +bpgdec$(EXE): bpgdec.o libbpg.a + $(CC) $(LDFLAGS) -o $@ $^ -lpng $(LIBS) + +bpgenc$(EXE): $(BPGENC_OBJS) + $(CXX) $(LDFLAGS) -o $@ $^ $(BPGENC_LIBS) + +bpgdec.js: $(LIBBPG_JS_OBJS) post.js + $(EMCC) $(EMLDFLAGS) -s TOTAL_MEMORY=33554432 -o $@ $(LIBBPG_JS_OBJS) + +bpgdec8b.js: $(LIBBPG_JS8_OBJS) post.js + $(EMCC) $(EMLDFLAGS) -s TOTAL_MEMORY=16777216 -o $@ $(LIBBPG_JS8_OBJS) + +size: + strip bpgdec + size bpgdec libbpg.o libavcodec/*.o libavutil/*.o | sort -n + gzip < bpgdec | wc + +install: bpgenc bpgdec + install -s -m 755 $^ $(prefix)/bin + +CLEAN_DIRS=doc html libavcodec libavutil \ + jctvc jctvc/TLibEncoder jctvc/TLibVideoIO jctvc/TLibCommon jctvc/libmd5 + +clean: + rm -f $(PROGS) *.o *.a *.d *~ $(addsuffix /*.o, $(CLEAN_DIRS)) \ + $(addsuffix /*.d, $(CLEAN_DIRS)) $(addsuffix /*~, $(CLEAN_DIRS)) \ + $(addsuffix /*.a, $(CLEAN_DIRS)) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.js.o: %.c + $(EMCC) $(EMCFLAGS) -c -o $@ $< + +%.js8.o: %.c + $(EMCC) $(EMCFLAGS) -c -o $@ $< + +-include $(wildcard *.d) +-include $(wildcard libavcodec/*.d) +-include $(wildcard libavutil/*.d) +-include $(wildcard jctvc/*.d) +-include $(wildcard jctvc/TLibEncoder/*.d) +-include $(wildcard jctvc/TLibVideoIO/*.d) +-include $(wildcard jctvc/TLibCommon/*.d) +-include $(wildcard jctvc/libmd5/*.d) diff --git a/README b/README new file mode 100644 index 0000000..1519794 --- /dev/null +++ b/README @@ -0,0 +1,174 @@ +BPG Image Encoder and Decoder +----------------------------- + +1) Quick introduction +--------------------- + +- Edit the Makefile to change the compile options (the default compile + options should be OK for Linux). Type 'make' to compile and 'make + install' to install the compiled binaries. + +- x265 usage: for much increased compression speed (but lower + quality), you can compile and install x265 and then enable its use + in the Makefile. x265 supports by default only 8 bits per component + and does not support monochrome encoding yet (hence no alpha nor + grayscale images can be encoded with it). + +- Emscripten usage: in order to generate the Javascript decoder, you + must install Emscripten and enable its use in the Makefile. + +- An HTML demonstration (with a precompiled Javascript decoder) is + available in html/index.html (if you use Chrome and want to use + file:// to access it, launch Chrome with the option + --allow-file-access-from-files). + +- The BPG file format is specified in doc/bpg_spec.txt. + +2) BPG encoder +-------------- + +The BPG command line encoder is 'bpgenc'. It takes JPEG or PNG images +as input. + +- Speed: by default bpgenc uses the JCTVC encoder which has a high + quality but is slow. If you compiled with x265, you can have a much + faster encoding with the '-e x265' option. With x265 you can also + select the encoding speed with the '-m' option (1 = fast, but larger + image, 9 = slower but smaller image). Warning: x265 does not support + monochrome (and alpha) yet, so you must use the JCTVC encoder for + these cases. + +- Bit depth: the default bit depth is 8. You can increase it to 10 + ('-b 10' option) to slightly increase the compression ratio. For web + publishing it is generally not a good idea because the Javascript + decoder uses more memory. + +- Lossless compression is supported as a bonus thru the HEVC lossless + capabilities. Use a PNG input in this case unless you know what you + do ! In case of a JPEG input, the compression is lossless related to + the JPEG YCbCr data, not the RGB data. In any case, the bit depth + should match the one of your picture otherwise the file size + increases a lot. By default the lossless mode sets the bit depth to + 8 bits. The prefered color space is set to "rgb". Notes: + + - lossless mode is less tested that the lossy mode but it usually + gives better results that PNG on photographic images. + + - the JCTVC encoder gives smaller images than the x265 encoder + with lossless compression. + +- There is a difference of interpretation of the quantizer parameter + (-q option) between the x265 and JCTVC encoder. The default value is + optimized for the JCTVC encoder, not for x265. We will try to align + the x265 value to JCTVC in the future. + +- By default, the JCTVC encoder is limited to a precision of 12 + bits. You can enable high bit depths (up to 14) by enabling the + Makefile define: USE_JCTVC_HIGH_BIT_DEPTH. The encoder is sligthly + slower in this case. + +- Color space and chroma format: + + * For JPEG input, the color space of the input image is not + modified (it is YCbCr, RGB, YCbCrK or CMYK). The chroma is + subsampled according to the preferred chroma format ('-f' + option). Images with vertically subsampled chroma are currently + not supported. + + * For PNG input, the input image is converted to the preferred + color space ('-c' option). Its chroma is then subsampled + according to the preferred chroma format. + + * grayscale images are kept unmodified. + +- Premultiplied alpha: by default bpgenc uses non-premultiplied alpha + to preserve the color components. However, premultiplied alpha + ('-premul' option) usually gives a better compression at the expense + of a loss in the color components. This loss is not an issue if the + image is not edited. + +- By default, bpgenc does not copy the metadata. You can copy them + with the '-keepmetadata' option. For JPEG input, EXIF, ICCP and XMP + are copied. For PNG input, ICCP is copied. + +3) BPG decoder +-------------- + +The BPG command line decoder is bpgdec. It outputs a PNG or PPM +image. Use a PPM output to get the fastest speed. + +- With the '-i' option, you have information about the BPG image (and +no decoded image is output). + +- The '-b' option selects the bit depth (8 or 16) of the PNG + output. It is independent of the internal BPG bit depth. + +4) BPG decoding library +----------------------- + +BPG images can be decoded in any program with the libbpg +library. + +The API is not considered stable yet so that the library is only +provided as a static one. + +Currently there is no similar library for encoding so you should +invoke the bpgenc utility. + +5) Javascript decoder +--------------------- + +bpgdec.js is a Javascript decoder supporting the BPG file +format. bpgdec8b.js is a specialized version limited to BPG images +using 8 bits per component. It is a little faster and consumes less +memory (16 MB instead of 32 MB by default, you can change the memory +configuration in the Makefile if you want to handle larger images). + +The Javascript decoder substitutes all the tags with a source +having a .bpg extension with a tag and decodes the BPG image +into it. Stylesheets are supported (the 'id' and 'class' attributes +are preserved). The 'width' and 'height' attributes are supported only +with pixel units. + +asm.js gives an interesting speed boost, so we hope that more browser +will support this Javascript subset. + +6) FFmpeg modifications +----------------------- + +- Completed support of chroma_format_idc = 0 (monochrome mode). + +- Fixed RDPCM support (intra predictions). + +- Reduced memory usage for the SAO loop filter. + +- Generated the IDCT coefficients dynamically to reduce the code size. + +- Added a 'dynamic bit depth' mode where all the bit depths from 8 to + 14 are supported without code duplication but slower decoding. + +- Added a modified SPS header to reduce the size of the BPG decoder + (the solution instead is to generate standard VPS and SPS headers + from the BPG header). + +- Added defines to keep only the HEVC intra code and suppress the + parsing of all the irrelevant NAL units. + +- Stripped FFmpeg from all codecs except HEVC and the necessary + support code. + +7) Licensing +------------ + +- libbpg and bpgenc are released under the LGPL license (the FFmpeg + part is under the LGPL, the BPG specific part is released under the + BSD license). + +- bpgenc is released under the BSD license (it includes the JCTVC code + which is released under the BSD license. The BPG specific part is + released under the BSD license). + +- BPG relies on the HEVC compression technology which may be protected + by patents in some countries. Most devices already include or will + include hardware HEVC support, so we suggest to use it if patents + are an issue. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..965065d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.9.3 diff --git a/bpgdec.c b/bpgdec.c new file mode 100644 index 0000000..3818b9c --- /dev/null +++ b/bpgdec.c @@ -0,0 +1,350 @@ +/* + * BPG decoder command line utility + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +/* define it to include PNG output */ +#define USE_PNG + +#ifdef USE_PNG +#include +#endif + +#include "libbpg.h" + +static void ppm_save(BPGDecoderContext *img, const char *filename) +{ + BPGImageInfo img_info_s, *img_info = &img_info_s; + FILE *f; + int w, h, y; + uint8_t *rgb_line; + + bpg_decoder_get_info(img, img_info); + + w = img_info->width; + h = img_info->height; + + rgb_line = malloc(3 * w); + + f = fopen(filename,"w"); + if (!f) { + fprintf(stderr, "%s: I/O error\n", filename); + exit(1); + } + + fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + + bpg_decoder_start(img, BPG_OUTPUT_FORMAT_RGB24); + for (y = 0; y < h; y++) { + bpg_decoder_get_line(img, rgb_line); + fwrite(rgb_line, 1, w * 3, f); + } + fclose(f); + + free(rgb_line); +} + +#ifdef USE_PNG +static void png_write_data (png_structp png_ptr, png_bytep data, + png_size_t length) +{ + FILE *f; + int ret; + + f = png_get_io_ptr(png_ptr); + ret = fwrite(data, 1, length, f); + if (ret != length) + png_error(png_ptr, "PNG Write Error"); +} + +static void png_save(BPGDecoderContext *img, const char *filename, int bit_depth) +{ + BPGImageInfo img_info_s, *img_info = &img_info_s; + FILE *f; + png_structp png_ptr; + png_infop info_ptr; + png_bytep row_pointer; + int y, color_type, bpp; + BPGDecoderOutputFormat out_fmt; + + if (bit_depth != 8 && bit_depth != 16) { + fprintf(stderr, "Only bit_depth = 8 or 16 are supported for PNG output\n"); + exit(1); + } + + bpg_decoder_get_info(img, img_info); + + f = fopen(filename, "wb"); + if (!f) { + fprintf(stderr, "%s: I/O error\n", filename); + exit(1); + } + + png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, + NULL, + NULL, /* error */ + NULL, /* warning */ + NULL, + NULL, + NULL); + info_ptr = png_create_info_struct(png_ptr); + png_set_write_fn(png_ptr, (png_voidp)f, &png_write_data, NULL); + + if (setjmp(png_jmpbuf(png_ptr)) != 0) { + fprintf(stderr, "PNG write error\n"); + exit(1); + } + + if (img_info->has_alpha) + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + color_type = PNG_COLOR_TYPE_RGB; + + png_set_IHDR(png_ptr, info_ptr, img_info->width, img_info->height, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr, info_ptr); + +#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ + if (bit_depth == 16) { + png_set_swap(png_ptr); + } +#endif + + if (bit_depth == 16) { + if (img_info->has_alpha) + out_fmt = BPG_OUTPUT_FORMAT_RGBA64; + else + out_fmt = BPG_OUTPUT_FORMAT_RGB48; + } else { + if (img_info->has_alpha) + out_fmt = BPG_OUTPUT_FORMAT_RGBA32; + else + out_fmt = BPG_OUTPUT_FORMAT_RGB24; + } + + bpg_decoder_start(img, out_fmt); + + bpp = (3 + img_info->has_alpha) * (bit_depth / 8); + row_pointer = (png_bytep)png_malloc(png_ptr, img_info->width * bpp); + for (y = 0; y < img_info->height; y++) { + bpg_decoder_get_line(img, row_pointer); + png_write_row(png_ptr, row_pointer); + } + png_free(png_ptr, row_pointer); + + png_write_end(png_ptr, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(f); +} +#endif /* USE_PNG */ + +static void bpg_show_info(const char *filename, int show_extensions) +{ + uint8_t *buf; + int buf_len, ret, buf_len_max; + FILE *f; + BPGImageInfo p_s, *p = &p_s; + BPGExtensionData *first_md, *md; + static const char *format_str[4] = { + "Gray", + "4:2:0", + "4:2:2", + "4:4:4", + }; + static const char *color_space_str[BPG_CS_COUNT] = { + "YCbCr", + "RGB", + "YCgCo", + "YCbCr_BT709", + "YCbCr_BT2020", + }; + static const char *extension_tag_str[] = { + "Unknown", + "EXIF", + "ICC profile", + "XMP", + "Thumbnail", + }; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Could not open %s\n", filename); + exit(1); + } + + if (show_extensions) { + fseek(f, 0, SEEK_END); + buf_len_max = ftell(f); + fseek(f, 0, SEEK_SET); + } else { + /* if no extension are shown, just need the header */ + buf_len_max = BPG_DECODER_INFO_BUF_SIZE; + } + buf = malloc(buf_len_max); + buf_len = fread(buf, 1, buf_len_max, f); + + ret = bpg_decoder_get_info_from_buf(p, show_extensions ? &first_md : NULL, + buf, buf_len); + free(buf); + fclose(f); + if (ret < 0) { + fprintf(stderr, "Not a BPG image\n"); + exit(1); + } + printf("size=%dx%d color_space=%s", + p->width, p->height, + p->format == BPG_FORMAT_GRAY ? "Gray" : color_space_str[p->color_space]); + if (p->has_w_plane) { + printf(" w_plane=%d", p->has_w_plane); + } + if (p->has_alpha) { + printf(" alpha=%d premul=%d", + p->has_alpha, p->premultiplied_alpha); + } + printf(" format=%s limited_range=%d bit_depth=%d\n", + format_str[p->format], + p->limited_range, + p->bit_depth); + + if (first_md) { + const char *tag_name; + printf("Extension data:\n"); + for(md = first_md; md != NULL; md = md->next) { + if (md->tag <= 4) + tag_name = extension_tag_str[md->tag]; + else + tag_name = extension_tag_str[0]; + printf(" tag=%d (%s) length=%d\n", + md->tag, tag_name, md->buf_len); + } + bpg_decoder_free_extension_data(first_md); + } +} + +static void help(void) +{ + printf("BPG Image Decoder version " CONFIG_BPG_VERSION "\n" + "usage: bpgdec [options] infile\n" + "Options:\n" + "-o outfile.[ppm|png] set the output filename (default = out.png)\n" + "-b bit_depth PNG output only: use bit_depth per component (8 or 16, default = 8)\n" + "-i display information about the image\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *f; + BPGDecoderContext *img; + uint8_t *buf; + int buf_len, bit_depth, c, show_info; + const char *outfilename, *filename, *p; + + outfilename = "out.png"; + bit_depth = 8; + show_info = 0; + for(;;) { + c = getopt(argc, argv, "ho:b:i"); + if (c == -1) + break; + switch(c) { + case 'h': + show_help: + help(); + break; + case 'o': + outfilename = optarg; + break; + case 'b': + bit_depth = atoi(optarg); + break; + case 'i': + show_info = 1; + break; + default: + exit(1); + } + } + + if (optind >= argc) + goto show_help; + + filename = argv[optind++]; + + if (show_info) { + bpg_show_info(filename, 1); + return 0; + } + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Could not open %s\n", filename); + exit(1); + } + + fseek(f, 0, SEEK_END); + buf_len = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = malloc(buf_len); + if (fread(buf, 1, buf_len, f) != buf_len) { + fprintf(stderr, "Error while reading file\n"); + exit(1); + } + + fclose(f); + + img = bpg_decoder_open(); + + if (bpg_decoder_decode(img, buf, buf_len) < 0) { + fprintf(stderr, "Could not decode image\n"); + exit(1); + } + free(buf); + +#ifdef USE_PNG + p = strrchr(outfilename, '.'); + if (p) + p++; + + if (p && strcasecmp(p, "ppm") != 0) { + png_save(img, outfilename, bit_depth); + } else +#endif + { + ppm_save(img, outfilename); + } + + bpg_decoder_close(img); + + return 0; +} diff --git a/bpgenc.c b/bpgenc.c new file mode 100644 index 0000000..3699700 --- /dev/null +++ b/bpgenc.c @@ -0,0 +1,2312 @@ +/* + * BPG encoder + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bpgenc.h" + +typedef uint16_t PIXEL; + +static void put_ue(uint8_t **pp, uint32_t v); + +static inline int clamp_pix(int a, int pixel_max) +{ + if (a < 0) + return 0; + else if (a > pixel_max) + return pixel_max; + else + return a; +} + +static inline int sub_mod_int(int a, int b, int m) +{ + a -= b; + if (a < 0) + a += m; + return a; +} + +static inline int add_mod_int(int a, int b, int m) +{ + a += b; + if (a >= m) + a -= m; + return a; +} + +typedef struct { + int c_shift; + int c_rnd; + int c_0_25, c_0_5, c_one; + int rgb_to_ycc[3 * 3]; + int y_one; + int y_offset; + int bit_depth; + int pixel_max; + int c_center; +} ColorConvertState; + +static void convert_init(ColorConvertState *s, int in_bit_depth, + int out_bit_depth, BPGColorSpaceEnum color_space, + int limited_range) +{ + double k_r, k_b, mult, mult_y, mult_c; + int in_pixel_max, out_pixel_max, c_shift, i; + double rgb_to_ycc[3 * 3]; + + /* XXX: could use one more bit */ + c_shift = 31 - out_bit_depth; + in_pixel_max = (1 << in_bit_depth) - 1; + out_pixel_max = (1 << out_bit_depth) - 1; + mult = (double)out_pixel_max * (1 << c_shift) / (double)in_pixel_max; + // printf("mult=%f c_shift=%d\n", mult, c_shift); + if (limited_range) { + mult_y = (double)(219 << (out_bit_depth - 8)) * (1 << c_shift) / + (double)in_pixel_max; + mult_c = (double)(224 << (out_bit_depth - 8)) * (1 << c_shift) / + (double)in_pixel_max; + } else { + mult_y = mult; + mult_c = mult; + } + switch(color_space) { + case BPG_CS_YCbCr: + k_r = 0.299; + k_b = 0.114; + goto convert_ycc; + + case BPG_CS_YCbCr_BT709: + k_r = 0.2126; + k_b = 0.0722; + goto convert_ycc; + + case BPG_CS_YCbCr_BT2020: + k_r = 0.2627; + k_b = 0.0593; + convert_ycc: + rgb_to_ycc[0] = k_r; + rgb_to_ycc[1] = 1 - k_r - k_b; + rgb_to_ycc[2] = k_b; + rgb_to_ycc[3] = -0.5 * k_r / (1 - k_b); + rgb_to_ycc[4] = -0.5 * (1 - k_r - k_b) / (1 - k_b); + rgb_to_ycc[5] = 0.5; + rgb_to_ycc[6] = 0.5; + rgb_to_ycc[7] = -0.5 * (1 - k_r - k_b) / (1 - k_r); + rgb_to_ycc[8] = -0.5 * k_b / (1 - k_r); + + for(i = 0; i < 3; i++) + s->rgb_to_ycc[i] = lrint(rgb_to_ycc[i] * mult_y); + for(i = 3; i < 9; i++) + s->rgb_to_ycc[i] = lrint(rgb_to_ycc[i] * mult_c); + break; + case BPG_CS_YCgCo: + s->c_0_25 = lrint(0.25 * mult_y); + s->c_0_5 = lrint(0.5 * mult_y); + break; + default: + break; + } + + s->c_one = lrint(mult); + s->c_shift = c_shift; + s->c_rnd = (1 << (c_shift - 1)); + if (limited_range) { + s->y_offset = s->c_rnd + (16 << (c_shift + out_bit_depth - 8)); + s->y_one = lrint(mult_y); + } else { + s->y_offset = s->c_rnd; + s->y_one = s->c_one; + } + + s->bit_depth = out_bit_depth; + s->c_center = 1 << (out_bit_depth - 1); + s->pixel_max = out_pixel_max; +} + +/* 8 bit input */ +static void rgb24_to_ycc(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint8_t *src = src1; + int i, r, g, b, c0, c1, c2, c3, c4, c5, c6, c7, c8, shift, rnd, center; + int pixel_max, y_offset; + + c0 = s->rgb_to_ycc[0]; + c1 = s->rgb_to_ycc[1]; + c2 = s->rgb_to_ycc[2]; + c3 = s->rgb_to_ycc[3]; + c4 = s->rgb_to_ycc[4]; + c5 = s->rgb_to_ycc[5]; + c6 = s->rgb_to_ycc[6]; + c7 = s->rgb_to_ycc[7]; + c8 = s->rgb_to_ycc[8]; + shift = s->c_shift; + rnd = s->c_rnd; + y_offset = s->y_offset; + center = s->c_center; + pixel_max = s->pixel_max; + for(i = 0; i < n; i++) { + r = src[0]; + g = src[1]; + b = src[2]; + y_ptr[i] = clamp_pix((c0 * r + c1 * g + c2 * b + + y_offset) >> shift, pixel_max); + cb_ptr[i] = clamp_pix(((c3 * r + c4 * g + c5 * b + + rnd) >> shift) + center, pixel_max); + cr_ptr[i] = clamp_pix(((c6 * r + c7 * g + c8 * b + + rnd) >> shift) + center, pixel_max); + src += incr; + } +} + +static void rgb24_to_rgb(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint8_t *src = src1; + int i, r, g, b, c, shift, rnd; + + c = s->y_one; + shift = s->c_shift; + rnd = s->y_offset; + for(i = 0; i < n; i++) { + r = src[0]; + g = src[1]; + b = src[2]; + y_ptr[i] = (c * g + rnd) >> shift; + cb_ptr[i] = (c * b + rnd) >> shift; + cr_ptr[i] = (c * r + rnd) >> shift; + src += incr; + } +} + +static void rgb24_to_ycgco(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint8_t *src = src1; + int i, r, g, b, t1, t2, pixel_max, c_0_5, c_0_25, rnd, shift, center; + int y_offset; + + c_0_25 = s->c_0_25; + c_0_5 = s->c_0_5; + rnd = s->c_rnd; + shift = s->c_shift; + pixel_max = s->pixel_max; + center = s->c_center; + y_offset = s->y_offset; + for(i = 0; i < n; i++) { + r = src[0]; + g = src[1]; + b = src[2]; + t1 = c_0_5 * g; + t2 = c_0_25 * (r + b); + y_ptr[i] = clamp_pix((t1 + t2 + y_offset) >> shift, pixel_max); + cb_ptr[i] = clamp_pix(((t1 - t2 + rnd) >> shift) + center, + pixel_max); + cr_ptr[i] = clamp_pix(((c_0_5 * (r - b) + + rnd) >> shift) + center, pixel_max); + src += incr; + } +} + +/* Note: used for alpha/W so no limited range */ +static void gray8_to_gray(ColorConvertState *s, + PIXEL *y_ptr, const uint8_t *src, int n, int incr) +{ + int i, g, c, shift, rnd; + + c = s->c_one; + shift = s->c_shift; + rnd = s->c_rnd; + for(i = 0; i < n; i++) { + g = src[0]; + y_ptr[i] = (c * g + rnd) >> shift; + src += incr; + } +} + +static void luma8_to_gray(ColorConvertState *s, + PIXEL *y_ptr, const uint8_t *src, int n, int incr) +{ + int i, g, c, shift, rnd; + + c = s->y_one; + shift = s->c_shift; + rnd = s->y_offset; + for(i = 0; i < n; i++) { + g = src[0]; + y_ptr[i] = (c * g + rnd) >> shift; + src += incr; + } +} + +/* 16 bit input */ + +static void rgb48_to_ycc(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint16_t *src = src1; + int i, r, g, b, c0, c1, c2, c3, c4, c5, c6, c7, c8, shift, rnd, center; + int pixel_max, y_offset; + + c0 = s->rgb_to_ycc[0]; + c1 = s->rgb_to_ycc[1]; + c2 = s->rgb_to_ycc[2]; + c3 = s->rgb_to_ycc[3]; + c4 = s->rgb_to_ycc[4]; + c5 = s->rgb_to_ycc[5]; + c6 = s->rgb_to_ycc[6]; + c7 = s->rgb_to_ycc[7]; + c8 = s->rgb_to_ycc[8]; + shift = s->c_shift; + rnd = s->c_rnd; + y_offset = s->y_offset; + center = s->c_center; + pixel_max = s->pixel_max; + for(i = 0; i < n; i++) { + r = src[0]; + g = src[1]; + b = src[2]; + y_ptr[i] = clamp_pix((c0 * r + c1 * g + c2 * b + + y_offset) >> shift, pixel_max); + cb_ptr[i] = clamp_pix(((c3 * r + c4 * g + c5 * b + + rnd) >> shift) + center, pixel_max); + cr_ptr[i] = clamp_pix(((c6 * r + c7 * g + c8 * b + + rnd) >> shift) + center, pixel_max); + src += incr; + } +} + +static void rgb48_to_ycgco(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint16_t *src = src1; + int i, r, g, b, t1, t2, pixel_max, c_0_5, c_0_25, rnd, shift, center; + int y_offset; + + c_0_25 = s->c_0_25; + c_0_5 = s->c_0_5; + rnd = s->c_rnd; + y_offset = s->y_offset; + shift = s->c_shift; + pixel_max = s->pixel_max; + center = s->c_center; + for(i = 0; i < n; i++) { + r = src[0]; + g = src[1]; + b = src[2]; + t1 = c_0_5 * g; + t2 = c_0_25 * (r + b); + y_ptr[i] = clamp_pix((t1 + t2 + y_offset) >> shift, pixel_max); + cb_ptr[i] = clamp_pix(((t1 - t2 + rnd) >> shift) + center, + pixel_max); + cr_ptr[i] = clamp_pix(((c_0_5 * (r - b) + + rnd) >> shift) + center, pixel_max); + src += incr; + } +} + +/* Note: use for alpha/W so no limited range */ +static void gray16_to_gray(ColorConvertState *s, + PIXEL *y_ptr, const uint16_t *src, int n, int incr) +{ + int i, g, c, shift, rnd; + + c = s->c_one; + shift = s->c_shift; + rnd = s->c_rnd; + for(i = 0; i < n; i++) { + g = src[0]; + y_ptr[i] = (c * g + rnd) >> shift; + src += incr; + } +} + +static void luma16_to_gray(ColorConvertState *s, + PIXEL *y_ptr, const uint16_t *src, int n, int incr) +{ + int i, g, c, shift, rnd; + + c = s->y_one; + shift = s->c_shift; + rnd = s->y_offset; + for(i = 0; i < n; i++) { + g = src[0]; + y_ptr[i] = (c * g + rnd) >> shift; + src += incr; + } +} + +static void rgb48_to_rgb(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src1, int n, int incr) +{ + const uint16_t *src = src1; + + luma16_to_gray(s, y_ptr, src + 1, n, incr); + luma16_to_gray(s, cb_ptr, src + 2, n, incr); + luma16_to_gray(s, cr_ptr, src + 0, n, incr); +} + +typedef void RGBConvertFunc(ColorConvertState *s, + PIXEL *y_ptr, PIXEL *cb_ptr, PIXEL *cr_ptr, + const void *src, int n, int incr); + +static RGBConvertFunc *rgb_to_cs[2][BPG_CS_COUNT] = { + { + rgb24_to_ycc, + rgb24_to_rgb, + rgb24_to_ycgco, + rgb24_to_ycc, + rgb24_to_ycc, + }, + { + rgb48_to_ycc, + rgb48_to_rgb, + rgb48_to_ycgco, + rgb48_to_ycc, + rgb48_to_ycc, + } +}; + +/* val = 1.0 - val */ +static void gray_one_minus(ColorConvertState *s, PIXEL *y_ptr, int n) +{ + int pixel_max = s->pixel_max; + int i; + + for(i = 0; i < n; i++) { + y_ptr[i] = pixel_max - y_ptr[i]; + } +} + +/* val = -val for chroma */ +static void gray_neg_c(ColorConvertState *s, PIXEL *y_ptr, int n) +{ + int pixel_max = s->pixel_max; + int i, v; + + for(i = 0; i < n; i++) { + v = y_ptr[i]; + if (v == 0) + v = pixel_max; + else + v = pixel_max + 1 - v; + y_ptr[i] = v; + } +} + + +/* decimation */ + +#define DTAPS2 5 +#define DTAPS (2 * DTAPS2) +#define DC0 57 +#define DC1 17 +#define DC2 (-8) +#define DC3 (-4) +#define DC4 2 + +static void decimate2_simple(PIXEL *dst, PIXEL *src, int n, int bit_depth) +{ + int n2, i, pixel_max; + pixel_max = (1 << bit_depth) - 1; + n2 = (n + 1) / 2; + for(i = 0; i < n2; i++) { + dst[i] = clamp_pix(((src[-4] + src[5]) * DC4 + + (src[-3] + src[4]) * DC3 + + (src[-2] + src[3]) * DC2 + + (src[-1] + src[2]) * DC1 + + (src[0] + src[1]) * DC0 + 64) >> 7, pixel_max); + src += 2; + } +} + +static void decimate2_h(PIXEL *dst, PIXEL *src, int n, int bit_depth) +{ + PIXEL *src1, v; + int d, i; + + d = DTAPS2; + /* add edge pixels */ + src1 = malloc(sizeof(PIXEL) * (n + 2 * d)); + v = src[0]; + for(i = 0; i < d; i++) + src1[i] = v; + memcpy(src1 + d, src, n * sizeof(PIXEL)); + v = src[n - 1]; + for(i = 0; i < d; i++) + src1[d + n + i] = v; + decimate2_simple(dst, src1 + d, n, bit_depth); + free(src1); +} + +/* same as decimate2_simple but with more precision and no saturation */ +static void decimate2_simple16(int16_t *dst, PIXEL *src, int n, int bit_depth) +{ + int n2, i, shift, rnd; + shift = bit_depth - 7; + rnd = 1 << (shift - 1); + n2 = (n + 1) / 2; + for(i = 0; i < n2; i++) { + dst[i] = ((src[-4] + src[5]) * DC4 + + (src[-3] + src[4]) * DC3 + + (src[-2] + src[3]) * DC2 + + (src[-1] + src[2]) * DC1 + + (src[0] + src[1]) * DC0 + rnd) >> shift; + src += 2; + } +} + +/* src1 is a temporary buffer of length n + 2 * DTAPS */ +static void decimate2_h16(int16_t *dst, PIXEL *src, int n, PIXEL *src1, + int bit_depth) +{ + PIXEL v; + int d, i; + + d = DTAPS2; + /* add edge pixels */ + v = src[0]; + for(i = 0; i < d; i++) + src1[i] = v; + memcpy(src1 + d, src, n * sizeof(PIXEL)); + v = src[n - 1]; + for(i = 0; i < d; i++) + src1[d + n + i] = v; + decimate2_simple16(dst, src1 + d, n, bit_depth); +} + +static void decimate2_v(PIXEL *dst, int16_t **src, int pos, int n, + int bit_depth) +{ + int16_t *src0, *src1, *src2, *src3, *src4, *src5, *srcm1, *srcm2, *srcm3, *srcm4; + int i, shift, offset, pixel_max; + + pos = sub_mod_int(pos, 4, DTAPS); + srcm4 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + srcm3 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + srcm2 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + srcm1 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src0 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src1 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src2 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src3 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src4 = src[pos]; + pos = add_mod_int(pos, 1, DTAPS); + src5 = src[pos]; + + shift = 21 - bit_depth; + offset = 1 << (shift - 1); + pixel_max = (1 << bit_depth) - 1; + for(i = 0; i < n; i++) { + dst[i] = clamp_pix(((srcm4[i] + src5[i]) * DC4 + + (srcm3[i] + src4[i]) * DC3 + + (srcm2[i] + src3[i]) * DC2 + + (srcm1[i] + src2[i]) * DC1 + + (src0[i] + src1[i]) * DC0 + offset) >> shift, pixel_max); + } +} + +/* Note: we do the horizontal decimation first to use less CPU cache */ +static void decimate2_hv(uint8_t *dst, int dst_linesize, + uint8_t *src, int src_linesize, + int w, int h, int bit_depth) +{ + PIXEL *buf1; + int16_t *buf2[DTAPS]; + int w2, pos, i, y, y1, y2; + + w2 = (w + 1) / 2; + + buf1 = malloc(sizeof(PIXEL) * (w + 2 * DTAPS)); + /* init line buffer */ + for(i = 0; i < DTAPS; i++) { + buf2[i] = malloc(sizeof(int16_t) * w2); + y = i; + if (y > DTAPS2) + y -= DTAPS; + if (y < 0) { + /* copy from first line */ + memcpy(buf2[i], buf2[0], sizeof(int16_t) * w2); + } else if (y >= h) { + /* copy from last line (only happens for small height) */ + memcpy(buf2[i], buf2[h - 1], sizeof(int16_t) * w2); + } else { + decimate2_h16(buf2[i], (PIXEL *)(src + src_linesize * y), w, + buf1, bit_depth); + } + } + + for(y = 0; y < h; y++) { + pos = y % DTAPS; + if ((y & 1) == 0) { + /* filter one line */ + y2 = y >> 1; + decimate2_v((PIXEL *)(dst + y2 * dst_linesize), buf2, + pos, w2, bit_depth); + } + /* add a new line in the buffer */ + y1 = y + DTAPS2 + 1; + pos = add_mod_int(pos, DTAPS2 + 1, DTAPS); + if (y1 >= h) { + /* copy last line */ + memcpy(buf2[pos], buf2[sub_mod_int(pos, 1, DTAPS)], + sizeof(int16_t) * w2); + } else { + /* horizontally decimate new line */ + decimate2_h16(buf2[pos], (PIXEL *)(src + src_linesize * y1), w, + buf1, bit_depth); + } + } + + for(i = 0; i < DTAPS; i++) + free(buf2[i]); + free(buf1); +} + +static void get_plane_res(Image *img, int *pw, int *ph, int i) +{ + if (img->format == BPG_FORMAT_420 && (i == 1 || i == 2)) { + *pw = (img->w + 1) / 2; + *ph = (img->h + 1) / 2; + } else if (img->format == BPG_FORMAT_422 && (i == 1 || i == 2)) { + *pw = (img->w + 1) / 2; + *ph = img->h; + } else { + *pw = img->w; + *ph = img->h; + } +} + +#define W_PAD 16 + +Image *image_alloc(int w, int h, BPGImageFormatEnum format, int has_alpha, + BPGColorSpaceEnum color_space, int bit_depth) +{ + Image *img; + int i, linesize, w1, h1, c_count; + + img = malloc(sizeof(Image)); + memset(img, 0, sizeof(*img)); + + img->w = w; + img->h = h; + img->format = format; + img->has_alpha = has_alpha; + img->bit_depth = bit_depth; + img->color_space = color_space; + img->pixel_shift = 1; + + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + if (has_alpha) + c_count++; + for(i = 0; i < c_count; i++) { + get_plane_res(img, &w1, &h1, i); + /* multiple of 16 pixels to add borders */ + w1 = (w1 + (W_PAD - 1)) & ~(W_PAD - 1); + h1 = (h1 + (W_PAD - 1)) & ~(W_PAD - 1); + + linesize = w1 << img->pixel_shift; + img->data[i] = malloc(linesize * h1); + img->linesize[i] = linesize; + } + return img; +} + +void image_free(Image *img) +{ + int i, c_count; + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + if (img->has_alpha) + c_count++; + for(i = 0; i < c_count; i++) + free(img->data[i]); + free(img); +} + +int image_ycc444_to_ycc422(Image *img) +{ + uint8_t *data1; + int w1, h1, bpp, linesize1, i, y; + + if (img->format != BPG_FORMAT_444 || img->pixel_shift != 1) + return -1; + bpp = 2; + w1 = (img->w + 1) / 2; + w1 = (w1 + (W_PAD - 1)) & ~(W_PAD - 1); + h1 = (img->h + (W_PAD - 1)) & ~(W_PAD - 1); + linesize1 = bpp * w1; + for(i = 1; i <= 2; i++) { + data1 = malloc(linesize1 * h1); + for(y = 0; y < img->h; y++) { + decimate2_h((PIXEL *)(data1 + y * linesize1), + (PIXEL *)(img->data[i] + y * img->linesize[i]), + img->w, img->bit_depth); + } + free(img->data[i]); + img->data[i] = data1; + img->linesize[i] = linesize1; + } + img->format = BPG_FORMAT_422; + return 0; +} + +int image_ycc444_to_ycc420(Image *img) +{ + uint8_t *data1; + int w1, h1, bpp, linesize1, i; + + if (img->format != BPG_FORMAT_444 || img->pixel_shift != 1) + return -1; + bpp = 2; + w1 = (img->w + 1) / 2; + h1 = (img->h + 1) / 2; + w1 = (w1 + (W_PAD - 1)) & ~(W_PAD - 1); + h1 = (h1 + (W_PAD - 1)) & ~(W_PAD - 1); + linesize1 = bpp * w1; + for(i = 1; i <= 2; i++) { + data1 = malloc(linesize1 * h1); + decimate2_hv(data1, linesize1, + img->data[i], img->linesize[i], + img->w, img->h, img->bit_depth); + free(img->data[i]); + img->data[i] = data1; + img->linesize[i] = linesize1; + } + img->format = BPG_FORMAT_420; + return 0; +} + +/* duplicate right and bottom samples so that the image has a width + and height multiple of cb_size (power of two) */ +void image_pad(Image *img, int cb_size) +{ + int w1, h1, x, y, c_count, c_w, c_h, c_w1, c_h1, h_shift, v_shift, c_idx; + PIXEL *ptr, v, *ptr1; + + assert(img->pixel_shift == 1); + if (cb_size <= 1) + return; + w1 = (img->w + cb_size - 1) & ~(cb_size - 1); + h1 = (img->h + cb_size - 1) & ~(cb_size - 1); + + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + if (img->has_alpha) + c_count++; + for(c_idx = 0; c_idx < c_count; c_idx++) { + if (img->format == BPG_FORMAT_420 && + (c_idx == 1 || c_idx == 2)) { + h_shift = 1; + v_shift = 1; + } else if (img->format == BPG_FORMAT_422 && + (c_idx == 1 || c_idx == 2)) { + h_shift = 1; + v_shift = 0; + } else { + h_shift = 0; + v_shift = 0; + } + + c_w = (img->w + h_shift) >> h_shift; + c_h = (img->h + v_shift) >> v_shift; + c_w1 = w1 >> h_shift; + c_h1 = h1 >> v_shift; + + /* pad horizontally */ + for(y = 0; y < c_h; y++) { + ptr = (PIXEL *)(img->data[c_idx] + img->linesize[c_idx] * y); + v = ptr[c_w - 1]; + for(x = c_w; x < c_w1; x++) { + ptr[x] = v; + } + } + + /* pad vertically */ + ptr1 = (PIXEL *)(img->data[c_idx] + img->linesize[c_idx] * (c_h - 1)); + for(y = c_h; y < c_h1; y++) { + ptr = (PIXEL *)(img->data[c_idx] + img->linesize[c_idx] * y); + memcpy(ptr, ptr1, c_w1 * sizeof(PIXEL)); + } + } + img->w = w1; + img->h = h1; +} + +/* convert the 16 bit components to 8 bits */ +void image_convert16to8(Image *img) +{ + int w, h, stride, y, x, c_count, i; + uint8_t *plane; + + if (img->bit_depth > 8 || img->pixel_shift != 1) + return; + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + if (img->has_alpha) + c_count++; + for(i = 0; i < c_count; i++) { + get_plane_res(img, &w, &h, i); + stride = w; + plane = malloc(stride * h); + for(y = 0; y < h; y++) { + const uint16_t *src; + uint8_t *dst; + dst = plane + stride * y; + src = (uint16_t *)(img->data[i] + img->linesize[i] * y); + for(x = 0; x < w; x++) + dst[x] = src[x]; + } + free(img->data[i]); + img->data[i] = plane; + img->linesize[i] = stride; + } + img->pixel_shift = 0; +} + +typedef struct BPGMetaData { + uint32_t tag; + uint8_t *buf; + int buf_len; + struct BPGMetaData *next; +} BPGMetaData; + +BPGMetaData *bpg_md_alloc(uint32_t tag) +{ + BPGMetaData *md; + md = malloc(sizeof(BPGMetaData)); + memset(md, 0, sizeof(*md)); + md->tag = tag; + return md; +} + +void bpg_md_free(BPGMetaData *md) +{ + BPGMetaData *md_next; + + while (md != NULL) { + md_next = md->next; + free(md->buf); + free(md); + md = md_next; + } +} + +Image *read_png(BPGMetaData **pmd, + FILE *f, BPGColorSpaceEnum color_space, int out_bit_depth, + int limited_range, int premultiplied_alpha) +{ + png_structp png_ptr; + png_infop info_ptr; + int bit_depth, color_type; + Image *img; + uint8_t **rows; + int y, has_alpha, linesize, bpp; + BPGImageFormatEnum format; + ColorConvertState cvt_s, *cvt = &cvt_s; + BPGMetaData *md, **plast_md, *first_md; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (png_ptr == NULL) { + return NULL; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + return NULL; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + png_init_io(png_ptr, f); + + png_read_info(png_ptr, info_ptr); + + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + color_type = png_get_color_type(png_ptr, info_ptr); + + switch (color_type) { + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(png_ptr); + bit_depth = 8; + break; + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth < 8) { + png_set_expand_gray_1_2_4_to_8(png_ptr); + bit_depth = 8; + } + break; + } + assert(bit_depth == 8 || bit_depth == 16); + +#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ + if (bit_depth == 16) { + png_set_swap(png_ptr); + } +#endif + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + format = BPG_FORMAT_GRAY; + color_space = BPG_CS_YCbCr; + } else { + format = BPG_FORMAT_444; + } + + has_alpha = (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_ptr); + has_alpha = 1; + } + + if (premultiplied_alpha) { + png_set_alpha_mode(png_ptr, PNG_ALPHA_ASSOCIATED, PNG_GAMMA_LINEAR); + } + + img = image_alloc(png_get_image_width(png_ptr, info_ptr), + png_get_image_height(png_ptr, info_ptr), + format, has_alpha, color_space, + out_bit_depth); + img->limited_range = limited_range; + img->premultiplied_alpha = premultiplied_alpha; + + rows = malloc(sizeof(rows[0]) * img->h); + if (format == BPG_FORMAT_GRAY) + bpp = (1 + has_alpha) * (bit_depth / 8); + else + bpp = (3 + has_alpha) * (bit_depth / 8); + linesize = bpp * img->w; + for (y = 0; y < img->h; y++) { + rows[y] = malloc(linesize); + } + + png_read_image(png_ptr, rows); + + convert_init(cvt, bit_depth, out_bit_depth, color_space, limited_range); + + if (format != BPG_FORMAT_GRAY) { + int idx; + RGBConvertFunc *convert_func; + + idx = (bit_depth == 16); + convert_func = rgb_to_cs[idx][color_space]; + + for (y = 0; y < img->h; y++) { + convert_func(cvt, (PIXEL *)(img->data[0] + y * img->linesize[0]), + (PIXEL *)(img->data[1] + y * img->linesize[1]), + (PIXEL *)(img->data[2] + y * img->linesize[2]), + rows[y], img->w, 3 + has_alpha); + if (has_alpha) { + if (idx) { + gray16_to_gray(cvt, (PIXEL *)(img->data[3] + y * img->linesize[3]), + (uint16_t *)rows[y] + 3, img->w, 4); + } else { + gray8_to_gray(cvt, (PIXEL *)(img->data[3] + y * img->linesize[3]), + rows[y] + 3, img->w, 4); + } + } + } + } else { + if (bit_depth == 16) { + for (y = 0; y < img->h; y++) { + luma16_to_gray(cvt, (PIXEL *)(img->data[0] + y * img->linesize[0]), + (uint16_t *)rows[y], img->w, 1 + has_alpha); + if (has_alpha) { + gray16_to_gray(cvt, (PIXEL *)(img->data[1] + y * img->linesize[1]), + (uint16_t *)rows[y] + 1, img->w, 2); + } + } + } else { + for (y = 0; y < img->h; y++) { + luma8_to_gray(cvt, (PIXEL *)(img->data[0] + y * img->linesize[0]), + rows[y], img->w, 1 + has_alpha); + if (has_alpha) { + gray8_to_gray(cvt, (PIXEL *)(img->data[1] + y * img->linesize[1]), + rows[y] + 1, img->w, 2); + } + } + } + } + + for (y = 0; y < img->h; y++) { + free(rows[y]); + } + free(rows); + + png_read_end(png_ptr, info_ptr); + + /* get the ICC profile if present */ + first_md = NULL; + plast_md = &first_md; + { + png_charp name; + int comp_type; + png_bytep iccp_buf; + png_uint_32 iccp_buf_len; + + if (png_get_iCCP(png_ptr, info_ptr, + &name, &comp_type, &iccp_buf, &iccp_buf_len) == + PNG_INFO_iCCP) { + md = bpg_md_alloc(BPG_EXTENSION_TAG_ICCP); + md->buf_len = iccp_buf_len; + md->buf = malloc(iccp_buf_len); + memcpy(md->buf, iccp_buf, iccp_buf_len); + *plast_md = md; + plast_md = &md->next; + } + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + *pmd = first_md; + return img; +} + +static BPGMetaData *jpeg_get_metadata(jpeg_saved_marker_ptr first_marker) +{ + static const char app1_exif[] = "Exif"; + static const char app1_xmp[] = "http://ns.adobe.com/xap/1.0/"; + static const char app2_iccp[] = "ICC_PROFILE"; + jpeg_saved_marker_ptr marker; + BPGMetaData *md, **plast_md, *first_md; + int has_exif, has_xmp, l, iccp_chunk_count, i; + jpeg_saved_marker_ptr iccp_chunks[256]; + + iccp_chunk_count = 0; + has_exif = 0; + has_xmp = 0; + first_md = NULL; + plast_md = &first_md; + for (marker = first_marker; marker != NULL; marker = marker->next) { +#if 0 + printf("marker=APP%d len=%d\n", + marker->marker - JPEG_APP0, marker->data_length); +#endif + if (!has_exif && marker->marker == JPEG_APP0 + 1 && + marker->data_length > sizeof(app1_exif) && + !memcmp(marker->data, app1_exif, sizeof(app1_exif))) { + md = bpg_md_alloc(BPG_EXTENSION_TAG_EXIF); + l = sizeof(app1_exif); + md->buf_len = marker->data_length - l; + md->buf = malloc(md->buf_len); + memcpy(md->buf, marker->data + l, md->buf_len); + *plast_md = md; + plast_md = &md->next; + has_exif = 1; + } else if (!has_xmp && marker->marker == JPEG_APP0 + 1 && + marker->data_length > sizeof(app1_xmp) && + !memcmp(marker->data, app1_xmp, sizeof(app1_xmp)) && + !has_xmp) { + md = bpg_md_alloc(BPG_EXTENSION_TAG_XMP); + l = sizeof(app1_xmp); + md->buf_len = marker->data_length - l; + md->buf = malloc(md->buf_len); + memcpy(md->buf, marker->data + l, md->buf_len); + *plast_md = md; + plast_md = &md->next; + has_xmp = 1; + } else if (marker->marker == JPEG_APP0 + 2 && + marker->data_length > (sizeof(app2_iccp) + 2) && + !memcmp(marker->data, app2_iccp, sizeof(app2_iccp))) { + int chunk_count, chunk_index; + l = sizeof(app2_iccp); + chunk_index = marker->data[l]; + chunk_count = marker->data[l]; + if (chunk_index == 0 || chunk_count == 0) + continue; + if (iccp_chunk_count == 0) { + iccp_chunk_count = chunk_count; + for(i = 0; i < chunk_count; i++) { + iccp_chunks[i] = NULL; + } + } else { + if (chunk_count != iccp_chunk_count) + continue; + } + if (chunk_index > iccp_chunk_count) + continue; + iccp_chunks[chunk_index - 1] = marker; + } + } + + if (iccp_chunk_count != 0) { + int len, hlen, idx; + /* check that no chunk are missing */ + len = 0; + hlen = sizeof(app2_iccp) + 2; + for(i = 0; i < iccp_chunk_count; i++) { + if (!iccp_chunks[i]) + break; + len += iccp_chunks[i]->data_length - hlen; + } + if (i == iccp_chunk_count) { + md = bpg_md_alloc(BPG_EXTENSION_TAG_ICCP); + md->buf_len = len; + md->buf = malloc(md->buf_len); + idx = 0; + for(i = 0; i < iccp_chunk_count; i++) { + l = iccp_chunks[i]->data_length - hlen; + memcpy(md->buf + idx, iccp_chunks[i]->data + hlen, l); + idx += l; + } + assert(idx == len); + *plast_md = md; + plast_md = &md->next; + } + } + return first_md; +} + +Image *read_jpeg(BPGMetaData **pmd, FILE *f, + int out_bit_depth) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW rows[4][16]; + JSAMPROW *plane_pointer[4]; + int w, h, w1, i, y_h, c_h, y, v_shift, c_w, y1, idx, c_idx; + int h1, plane_idx[4], has_alpha, has_w_plane; + Image *img; + BPGImageFormatEnum format; + BPGColorSpaceEnum color_space; + ColorConvertState cvt_s, *cvt = &cvt_s; + BPGMetaData *first_md = NULL; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + jpeg_save_markers(&cinfo, JPEG_APP0 + 1, 65535); + jpeg_save_markers(&cinfo, JPEG_APP0 + 2, 65535); + + jpeg_stdio_src(&cinfo, f); + + jpeg_read_header(&cinfo, TRUE); + + cinfo.raw_data_out = TRUE; + cinfo.do_fancy_upsampling = FALSE; + + jpeg_start_decompress(&cinfo); + + w = cinfo.output_width; + h = cinfo.output_height; + + has_w_plane = 0; + switch(cinfo.jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo.num_components != 1) + goto unsupported; + color_space = BPG_CS_YCbCr; + break; + case JCS_YCbCr: + if (cinfo.num_components != 3) + goto unsupported; + color_space = BPG_CS_YCbCr; + break; + case JCS_RGB: + if (cinfo.num_components != 3) + goto unsupported; + color_space = BPG_CS_RGB; + break; + case JCS_YCCK: + if (cinfo.num_components != 4) + goto unsupported; + color_space = BPG_CS_YCbCr; + has_w_plane = 1; + break; + case JCS_CMYK: + if (cinfo.num_components != 4) + goto unsupported; + color_space = BPG_CS_RGB; + has_w_plane = 1; + break; + default: + unsupported: + fprintf(stderr, "Unsupported JPEG colorspace (n=%d cs=%d)\n", + cinfo.num_components, cinfo.jpeg_color_space); + img = NULL; + goto the_end; + } + + if (cinfo.num_components == 1) { + format = BPG_FORMAT_GRAY; + v_shift = 0; + } else if (cinfo.max_v_samp_factor == 1 && + cinfo.max_h_samp_factor == 1) { + format = BPG_FORMAT_444; + v_shift = 0; + } else if (cinfo.max_v_samp_factor == 2 && + cinfo.max_h_samp_factor == 2) { + format = BPG_FORMAT_420; + v_shift = 1; + } else if (cinfo.max_v_samp_factor == 1 && + cinfo.max_h_samp_factor == 2) { + format = BPG_FORMAT_422; + v_shift = 0; + } else { + fprintf(stderr, "Unsupported JPEG subsampling format\n"); + img = NULL; + goto the_end; + } + + has_alpha = (cinfo.num_components == 4); + img = image_alloc(w, h, format, has_alpha, color_space, out_bit_depth); + img->has_w_plane = has_w_plane; + + y_h = 8 * cinfo.max_v_samp_factor; + if (cinfo.num_components == 1) { + c_h = 0; + c_w = 0; + } else { + c_h = 8; + if (cinfo.max_h_samp_factor == 2) + c_w = (w + 1) / 2; + else + c_w = w; + } + w1 = (w + 15) & ~15; + for(c_idx = 0; c_idx < cinfo.num_components; c_idx++) { + if (c_idx == 1 || c_idx == 2) { + h1 = c_h; + } else { + h1 = y_h; + } + for(i = 0; i < h1; i++) { + rows[c_idx][i] = malloc(w1); + } + plane_pointer[c_idx] = rows[c_idx]; + } + + if (color_space == BPG_CS_RGB) { + plane_idx[0] = 2; + plane_idx[1] = 0; + plane_idx[2] = 1; + } else { + plane_idx[0] = 0; + plane_idx[1] = 1; + plane_idx[2] = 2; + } + plane_idx[3] = 3; + + convert_init(cvt, 8, out_bit_depth, color_space, 0); + + while (cinfo.output_scanline < cinfo.output_height) { + y = cinfo.output_scanline; + jpeg_read_raw_data(&cinfo, plane_pointer, y_h); + + for(c_idx = 0; c_idx < cinfo.num_components; c_idx++) { + if (c_idx == 1 || c_idx == 2) { + h1 = c_h; + w1 = c_w; + y1 = (y >> v_shift); + } else { + h1 = y_h; + w1 = img->w; + y1 = y; + } + idx = plane_idx[c_idx]; + for(i = 0; i < h1; i++) { + PIXEL *ptr; + ptr = (PIXEL *)(img->data[idx] + + img->linesize[idx] * (y1 + i)); + gray8_to_gray(cvt, ptr, rows[c_idx][i], w1, 1); + if (color_space == BPG_CS_YCbCr && has_w_plane) { + /* negate color */ + if (c_idx == 0) { + gray_one_minus(cvt, ptr, w1); + } else if (c_idx <= 2) { + gray_neg_c(cvt, ptr, w1); + } + } + } + } + } + + for(c_idx = 0; c_idx < cinfo.num_components; c_idx++) { + if (c_idx == 1 || c_idx == 2) { + h1 = c_h; + } else { + h1 = y_h; + } + for(i = 0; i < h1; i++) { + free(rows[c_idx][i]); + } + } + + first_md = jpeg_get_metadata(cinfo.marker_list); + + the_end: + jpeg_finish_decompress(&cinfo); + + jpeg_destroy_decompress(&cinfo); + *pmd = first_md; + return img; +} + +void save_yuv(Image *img, const char *filename) +{ + int c_w, c_h, i, c_count, y; + FILE *f; + + f = fopen(filename, "wb"); + if (!f) { + fprintf(stderr, "Could not open %s\n", filename); + exit(1); + } + + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + for(i = 0; i < c_count; i++) { + get_plane_res(img, &c_w, &c_h, i); + for(y = 0; y < c_h; y++) { + fwrite(img->data[i] + y * img->linesize[i], + 1, c_w << img->pixel_shift, f); + } + } + fclose(f); +} + + +/* return the position of the end of the NAL or -1 if error */ +static int extract_nal(uint8_t **pnal_buf, int *pnal_len, + const uint8_t *buf, int buf_len) +{ + int idx, start, end, len; + uint8_t *nal_buf; + int nal_len; + + idx = 0; + if (buf_len < 6 || buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 1) + return -1; + idx += 4; + start = idx; + /* find the last byte */ + for(;;) { + if (idx + 2 >= buf_len) + break; + if (buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 1) + break; + if (idx + 3 < buf_len && + buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 0 && buf[idx + 3] == 1) + break; + idx++; + } + end = idx; + len = end - start; + + nal_buf = malloc(len); + nal_len = 0; + idx = start; + while (idx < end) { + if (idx + 2 < end && buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 3) { + nal_buf[nal_len++] = 0; + nal_buf[nal_len++] = 0; + idx += 3; + } else { + nal_buf[nal_len++] = buf[idx++]; + } + } + while (idx < end) { + nal_buf[nal_len++] = buf[idx++]; + } + *pnal_buf = nal_buf; + *pnal_len = nal_len; + return idx; +} + +/* big endian variable length 7 bit encoding */ +static void put_ue(uint8_t **pp, uint32_t v) +{ + uint8_t *p = *pp; + int i, j; + + for(i = 1; i < 5; i++) { + if (v < (1 << (7 * i))) + break; + } + for(j = i - 1; j >= 1; j--) + *p++ = ((v >> (7 * j)) & 0x7f) | 0x80; + *p++ = v & 0x7f; + *pp = p; +} + +typedef struct { + const uint8_t *buf; + int idx; + int buf_len; +} GetBitState; + +static void init_get_bits(GetBitState *s, const uint8_t *buf, int buf_len) +{ + s->buf = buf; + s->buf_len = buf_len; + s->idx = 0; +} + +static void skip_bits(GetBitState *s, int n) +{ + s->idx += n; +} + +/* 1 <= n <= 25. return '0' bits if past the end of the buffer. */ +static uint32_t get_bits(GetBitState *s, int n) +{ + const uint8_t *buf = s->buf; + int p, i; + uint32_t v; + + p = s->idx >> 3; + if ((p + 3) < s->buf_len) { + v = (buf[p] << 24) | (buf[p + 1] << 16) | + (buf[p + 2] << 8) | buf[p + 3]; + } else { + v = 0; + for(i = 0; i < 3; i++) { + if ((p + i) < s->buf_len) + v |= buf[p + i] << (24 - i * 8); + } + } + v = (v >> (32 - (s->idx & 7) - n)) & ((1 << n) - 1); + s->idx += n; + return v; +} + +/* 1 <= n <= 32 */ +static uint32_t get_bits_long(GetBitState *s, int n) +{ + uint32_t v; + + if (n <= 25) { + v = get_bits(s, n); + } else { + n -= 16; + v = get_bits(s, 16) << n; + v |= get_bits(s, n); + } + return v; +} + +/* at most 32 bits are supported */ +static uint32_t get_ue_golomb(GetBitState *s) +{ + int i; + i = 0; + for(;;) { + if (get_bits(s, 1)) + break; + i++; + if (i == 32) + return 0xffffffff; + } + if (i == 0) + return 0; + else + return ((1 << i) | get_bits_long(s, i)) - 1; +} + +typedef struct { + uint8_t *buf; + int idx; +} PutBitState; + +static void init_put_bits(PutBitState *s, uint8_t *buf) +{ + s->buf = buf; + s->idx = 0; +} + +static void put_bit(PutBitState *s, int bit) +{ + s->buf[s->idx >> 3] |= bit << (7 - (s->idx & 7)); + s->idx++; +} + +static void put_bits(PutBitState *s, int n, uint32_t v) +{ + int i; + + for(i = 0; i < n; i++) { + put_bit(s, (v >> (n - 1 - i)) & 1); + } +} + +static void put_ue_golomb(PutBitState *s, uint32_t v) +{ + uint32_t a; + int n; + + v++; + n = 0; + a = v; + while (a != 0) { + a >>= 1; + n++; + } + if (n > 1) + put_bits(s, n - 1, 0); + put_bits(s, n, v); +} + +/* suppress the VPS NAL and keep only the useful part of the SPS + header. The decoder can rebuild a valid HEVC stream if needed. */ +static int build_modified_hevc(uint8_t **pout_buf, + const uint8_t *buf, int buf_len) +{ + int nal_unit_type, nal_len, idx, i, ret, msps_buf_len; + int out_buf_len, out_buf_len_max; + uint8_t *nal_buf, *msps_buf, *out_buf; + GetBitState gb_s, *gb = &gb_s; + PutBitState pb_s, *pb = &pb_s; + uint8_t *p; + + idx = extract_nal(&nal_buf, &nal_len, buf, buf_len); + if (idx < 0) + return -1; + if (nal_len < 2) { + free(nal_buf); + return -1; + } + nal_unit_type = (nal_buf[0] >> 1) & 0x3f; + free(nal_buf); + if (nal_unit_type != 32) { + fprintf(stderr, "expecting VPS nal (%d)\n", nal_unit_type); + return -1; /* expect VPS nal */ + } + + ret = extract_nal(&nal_buf, &nal_len, buf + idx, buf_len); + if (ret < 0) + return -1; + idx += ret; + if (nal_len < 2) + return -1; + nal_unit_type = (nal_buf[0] >> 1) & 0x3f; + if (nal_unit_type != 33) { + fprintf(stderr, "expecting SPS nal (%d)\n", nal_unit_type); + return -1; /* expect SPS nal */ + } + /* skip the next start code */ + if (idx + 3 < buf_len && + buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 0 && buf[idx + 3] == 1) { + idx += 4; + } else if (idx + 2 < buf_len && + buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 1) { + idx += 3; + } + + /* skip the initial part of the SPS up to and including + log2_min_cb_size */ + { + int vps_id, max_sub_layers, profile_idc, sps_id; + int chroma_format_idc, width, height, bit_depth_luma, bit_depth_chroma; + int log2_max_poc_lsb, sublayer_ordering_info, log2_min_cb_size; + int log2_diff_max_min_coding_block_size, log2_min_tb_size; + int log2_diff_max_min_transform_block_size; + int max_transform_hierarchy_depth_inter; + int max_transform_hierarchy_depth_intra; + int scaling_list_enable_flag, amp_enabled_flag, sao_enabled; + int pcm_enabled_flag, nb_st_rps; + int long_term_ref_pics_present_flag, sps_strong_intra_smoothing_enable_flag, vui_present; + int pcm_sample_bit_depth_luma_minus1; + int pcm_sample_bit_depth_chroma_minus1; + int log2_min_pcm_luma_coding_block_size_minus3; + int log2_diff_max_min_pcm_luma_coding_block_size; + int pcm_loop_filter_disabled_flag; + int sps_extension_flag, sps_range_extension_flag, sps_extension_7bits; + int sps_range_extension_flags; + + init_get_bits(gb, nal_buf, nal_len); + skip_bits(gb, 16); /* nal header */ + vps_id = get_bits(gb, 4); + if (vps_id != 0) { + fprintf(stderr, "VPS id 0 expected\n"); + return -1; + } + max_sub_layers = get_bits(gb, 3); + if (max_sub_layers != 0) { + fprintf(stderr, "max_sub_layers == 0 expected\n"); + return -1; + } + skip_bits(gb, 1); /* temporal_id_nesting_flag */ + /* profile tier level */ + skip_bits(gb, 2); /* profile_space */ + skip_bits(gb, 1); /* tier_flag */ + profile_idc = get_bits(gb, 5); + for(i = 0; i < 32; i++) { + skip_bits(gb, 1); /* profile_compatibility_flag */ + } + skip_bits(gb, 1); /* progressive_source_flag */ + skip_bits(gb, 1); /* interlaced_source_flag */ + skip_bits(gb, 1); /* non_packed_constraint_flag */ + skip_bits(gb, 1); /* frame_only_constraint_flag */ + skip_bits(gb, 44); /* XXX_reserved_zero_44 */ + skip_bits(gb, 8); /* level_idc */ + + sps_id = get_ue_golomb(gb); + if (sps_id != 0) { + fprintf(stderr, "SPS id 0 expected (%d)\n", sps_id); + return -1; + } + chroma_format_idc = get_ue_golomb(gb); + if (chroma_format_idc == 3) { + get_bits(gb, 1); /* separate_colour_plane_flag */ + } + width = get_ue_golomb(gb); + height = get_ue_golomb(gb); + /* pic conformance_flag */ + if (get_bits(gb, 1)) { + get_ue_golomb(gb); /* left_offset */ + get_ue_golomb(gb); /* right_offset */ + get_ue_golomb(gb); /* top_offset */ + get_ue_golomb(gb); /* bottom_offset */ + } + bit_depth_luma = get_ue_golomb(gb) + 8; + bit_depth_chroma = get_ue_golomb(gb) + 8; + log2_max_poc_lsb = get_ue_golomb(gb) + 4; + if (log2_max_poc_lsb != 8) { + fprintf(stderr, "log2_max_poc_lsb must be 8 (%d)\n", log2_max_poc_lsb); + return -1; + } + sublayer_ordering_info = get_bits(gb, 1); + get_ue_golomb(gb); /* max_dec_pic_buffering */ + get_ue_golomb(gb); /* num_reorder_pics */ + get_ue_golomb(gb); /* max_latency_increase */ + + log2_min_cb_size = get_ue_golomb(gb) + 3; + log2_diff_max_min_coding_block_size = get_ue_golomb(gb); + log2_min_tb_size = get_ue_golomb(gb) + 2; + log2_diff_max_min_transform_block_size = get_ue_golomb(gb); + + max_transform_hierarchy_depth_inter = get_ue_golomb(gb); + max_transform_hierarchy_depth_intra = get_ue_golomb(gb); + + scaling_list_enable_flag = get_bits(gb, 1); + if (scaling_list_enable_flag != 0) { + fprintf(stderr, "scaling_list_enable_flag must be 0\n"); + return -1; + } + amp_enabled_flag = get_bits(gb, 1); + sao_enabled = get_bits(gb, 1); + pcm_enabled_flag = get_bits(gb, 1); + if (pcm_enabled_flag) { + pcm_sample_bit_depth_luma_minus1 = get_bits(gb, 4); + pcm_sample_bit_depth_chroma_minus1 = get_bits(gb, 4); + log2_min_pcm_luma_coding_block_size_minus3 = get_ue_golomb(gb); + log2_diff_max_min_pcm_luma_coding_block_size = get_ue_golomb(gb); + pcm_loop_filter_disabled_flag = get_bits(gb, 1); + } + nb_st_rps = get_ue_golomb(gb); + if (nb_st_rps != 0) { + fprintf(stderr, "nb_st_rps must be 0 (%d)\n", nb_st_rps); + return -1; + } + long_term_ref_pics_present_flag = get_bits(gb, 1); + if (long_term_ref_pics_present_flag) { + fprintf(stderr, "nlong_term_ref_pics_present_flag must be 0 (%d)\n", nb_st_rps); + return -1; + } + get_bits(gb, 1); /* sps_temporal_mvp_enabled_flag */ + sps_strong_intra_smoothing_enable_flag = get_bits(gb, 1); + vui_present = get_bits(gb, 1); + if (vui_present) { + int sar_present, sar_idx, overscan_info_present_flag; + int video_signal_type_present_flag, chroma_loc_info_present_flag; + int default_display_window_flag, vui_timing_info_present_flag; + int vui_poc_proportional_to_timing_flag; + int vui_hrd_parameters_present_flag, bitstream_restriction_flag; + + sar_present = get_bits(gb, 1); + sar_idx = get_bits(gb, 8); + if (sar_idx == 255) { + skip_bits(gb, 16); /* sar_num */ + skip_bits(gb, 16); /* sar_den */ + } + + overscan_info_present_flag = get_bits(gb, 1); + if (overscan_info_present_flag) { + skip_bits(gb, 1); /* overscan_appropriate_flag */ + } + + video_signal_type_present_flag = get_bits(gb, 1); + if (video_signal_type_present_flag) { + fprintf(stderr, "video_signal_type_present_flag must be 0\n"); + return -1; + } + chroma_loc_info_present_flag = get_bits(gb, 1); + if (chroma_loc_info_present_flag) { + get_ue_golomb(gb); + get_ue_golomb(gb); + } + skip_bits(gb, 1); /* neutra_chroma_indication_flag */ + skip_bits(gb, 1); + skip_bits(gb, 1); + default_display_window_flag = get_bits(gb, 1); + if (default_display_window_flag) { + fprintf(stderr, "default_display_window_flag must be 0\n"); + return -1; + } + vui_timing_info_present_flag = get_bits(gb, 1); + if (vui_timing_info_present_flag) { + skip_bits(gb, 32); + skip_bits(gb, 32); + vui_poc_proportional_to_timing_flag = get_bits(gb, 1); + if (vui_poc_proportional_to_timing_flag) { + get_ue_golomb(gb); + } + vui_hrd_parameters_present_flag = get_bits(gb, 1); + if (vui_hrd_parameters_present_flag) { + fprintf(stderr, "vui_hrd_parameters_present_flag must be 0\n"); + return -1; + } + } + bitstream_restriction_flag = get_bits(gb, 1); + if (bitstream_restriction_flag) { + skip_bits(gb, 1); + skip_bits(gb, 1); + skip_bits(gb, 1); + get_ue_golomb(gb); + get_ue_golomb(gb); + get_ue_golomb(gb); + get_ue_golomb(gb); + get_ue_golomb(gb); + } + } + sps_extension_flag = get_bits(gb, 1); + sps_range_extension_flag = 0; + sps_range_extension_flags = 0; + if (sps_extension_flag) { + sps_range_extension_flag = get_bits(gb, 1); + sps_extension_7bits = get_bits(gb, 7); + if (sps_extension_7bits != 0) { + fprintf(stderr, "sps_extension_7bits must be 0\n"); + return -1; + } + if (sps_range_extension_flag) { + sps_range_extension_flags = get_bits(gb, 9); + if (sps_range_extension_flags & ((1 << (8 - 3)) | + (1 << (8 - 4)) | + (1 << (8 - 6)) | + (1 << (8 - 8)))) { + fprintf(stderr, "unsupported range extensions (0x%x)\n", + sps_range_extension_flags); + return -1; + } + } + } + + /* build the modified SPS */ + msps_buf = malloc(nal_len + 32); + memset(msps_buf, 0, nal_len + 16); + + init_put_bits(pb, msps_buf); + put_ue_golomb(pb, log2_min_cb_size - 3); + put_ue_golomb(pb, log2_diff_max_min_coding_block_size); + put_ue_golomb(pb, log2_min_tb_size - 2); + put_ue_golomb(pb, log2_diff_max_min_transform_block_size); + put_ue_golomb(pb, max_transform_hierarchy_depth_intra); + put_bits(pb, 1, sao_enabled); + put_bits(pb, 1, pcm_enabled_flag); + if (pcm_enabled_flag) { + put_bits(pb, 4, pcm_sample_bit_depth_luma_minus1); + put_bits(pb, 4, pcm_sample_bit_depth_chroma_minus1); + put_ue_golomb(pb, log2_min_pcm_luma_coding_block_size_minus3); + put_ue_golomb(pb, log2_diff_max_min_pcm_luma_coding_block_size); + put_bits(pb, 1, pcm_loop_filter_disabled_flag); + } + put_bits(pb, 1, sps_strong_intra_smoothing_enable_flag); + put_bits(pb, 1, sps_extension_flag); + if (sps_extension_flag) { + put_bits(pb, 1, sps_range_extension_flag); + put_bits(pb, 7, 0); + if (sps_range_extension_flag) { + put_bits(pb, 9, sps_range_extension_flags); + } + } + msps_buf_len = (pb->idx + 7) >> 3; + + out_buf_len_max = 5 + msps_buf_len + (buf_len - idx); + out_buf = malloc(out_buf_len_max); + + // printf("msps_n_bits=%d\n", pb->idx); + p = out_buf; + put_ue(&p, msps_buf_len); /* header length */ + + memcpy(p, msps_buf, msps_buf_len); + p += msps_buf_len; + + memcpy(p, buf + idx, buf_len - idx); + p += buf_len - idx; + + out_buf_len = p - out_buf; + free(msps_buf); + free(nal_buf); + } + *pout_buf = out_buf; + return out_buf_len; +} + +typedef enum { +#if defined(USE_JCTVC) + HEVC_ENCODER_JCTVC, +#endif +#if defined(USE_X265) + HEVC_ENCODER_X265, +#endif + + HEVC_ENCODER_COUNT, +} HEVCEncoderEnum; + +static char *hevc_encoder_name[HEVC_ENCODER_COUNT] = { +#if defined(USE_JCTVC) + "jctvc", +#endif +#if defined(USE_X265) + "x265", +#endif +}; + +static int hevc_encode_picture2(uint8_t **pbuf, Image *img, + HEVCEncodeParams *params, + HEVCEncoderEnum encoder_type) +{ + uint8_t *buf, *out_buf; + int buf_len, out_buf_len; + + switch(encoder_type) { +#if defined(USE_JCTVC) + case HEVC_ENCODER_JCTVC: + buf_len = jctvc_encode_picture(&buf, img, params); + break; +#endif +#if defined(USE_X265) + case HEVC_ENCODER_X265: + buf_len = x265_encode_picture(&buf, img, params); + break; +#endif + default: + buf_len = -1; + break; + } + if (buf_len < 0) { + *pbuf = NULL; + return -1; + } + out_buf_len = build_modified_hevc(&out_buf, buf, buf_len); + free(buf); + if (out_buf_len < 0) { + *pbuf = NULL; + return -1; + } + *pbuf = out_buf; + return out_buf_len; +} + + +#define IMAGE_HEADER_MAGIC 0x425047fb + +#define DEFAULT_OUTFILENAME "out.bpg" +#define DEFAULT_QP 28 +#define DEFAULT_BIT_DEPTH 8 + +#ifdef RExt__HIGH_BIT_DEPTH_SUPPORT +#define BIT_DEPTH_MAX 14 +#else +#define BIT_DEPTH_MAX 12 +#endif +#define DEFAULT_COMPRESS_LEVEL 8 + +void help(int is_full) +{ + char hevc_encoders[128]; + int i; + + hevc_encoders[0] = '\0'; + for(i = 0; i < HEVC_ENCODER_COUNT; i++) { + if (i != 0) + strcat(hevc_encoders, " "); + strcat(hevc_encoders, hevc_encoder_name[i]); + } + + printf("BPG Image Encoder version " CONFIG_BPG_VERSION "\n" + "usage: bpgenc [options] infile.[jpg|png]\n" + "\n" + "Main options:\n" + "-h show the full help (including the advanced options)\n" + "-o outfile set output filename (default = %s)\n" + "-q qp set quantizer parameter (smaller gives better quality,\n" + " range: 0-51, default = %d)\n" + "-f cfmt set the preferred chroma format (420, 422, 444,\n" + " default=420)\n" + "-c color_space set the preferred color space (ycbcr, rgb, ycgco,\n" + " ycbcr_bt709, ycbcr_bt2020, default=ycbcr)\n" + "-b bit_depth set the bit depth (8 to %d, default = %d)\n" + "-lossless enable lossless mode\n" + "-e encoder select the HEVC encoder (%s, default = %s)\n" + "-m level select the compression level (1=fast, 9=slow, default = %d)\n" + , DEFAULT_OUTFILENAME, DEFAULT_QP, BIT_DEPTH_MAX, DEFAULT_BIT_DEPTH, + hevc_encoders, hevc_encoder_name[0], DEFAULT_COMPRESS_LEVEL); + if (is_full) { + printf("\nAdvanced options:\n" + "-alphaq set quantizer parameter for the alpha channel (default = same as -q value)\n" + "-premul store the color with premultiplied alpha\n" + "-limitedrange encode the color data with the limited range of video\n" + "-hash include MD5 hash in HEVC bitstream\n" + "-keepmetadata keep the metadata (from JPEG: EXIF, ICC profile, XMP, from PNG: ICC profile)\n" + "-v show debug messages\n" + ); + } + + exit(1); +} + +struct option long_opts[] = { + { "hash", no_argument }, + { "keepmetadata", no_argument }, + { "alphaq", required_argument }, + { "lossless", no_argument }, + { "limitedrange", no_argument }, + { "premul", no_argument }, + { NULL }, +}; + +int main(int argc, char **argv) +{ + const char *infilename, *outfilename; + Image *img, *img_alpha; + HEVCEncodeParams p_s, *p = &p_s; + uint8_t *out_buf, *alpha_buf, *extension_buf; + int out_buf_len, alpha_buf_len, verbose; + FILE *f; + int qp, c, option_index, sei_decoded_picture_hash, is_png, extension_buf_len; + int keep_metadata, cb_size, width, height, compress_level, alpha_qp; + int bit_depth, lossless_mode, i, limited_range, premultiplied_alpha; + BPGImageFormatEnum format; + BPGColorSpaceEnum color_space; + BPGMetaData *md; + HEVCEncoderEnum encoder_type; + + outfilename = DEFAULT_OUTFILENAME; + qp = DEFAULT_QP; + alpha_qp = -1; + sei_decoded_picture_hash = 0; + format = BPG_FORMAT_420; + color_space = BPG_CS_YCbCr; + keep_metadata = 0; + verbose = 0; + compress_level = DEFAULT_COMPRESS_LEVEL; + bit_depth = DEFAULT_BIT_DEPTH; + lossless_mode = 0; + encoder_type = 0; + limited_range = 0; + premultiplied_alpha = 0; + + for(;;) { + c = getopt_long_only(argc, argv, "q:o:hf:c:vm:b:e:", long_opts, &option_index); + if (c == -1) + break; + switch(c) { + case 0: + switch(option_index) { + case 0: + sei_decoded_picture_hash = 1; + break; + case 1: + keep_metadata = 1; + break; + case 2: + alpha_qp = atoi(optarg); + if (alpha_qp < 0 || alpha_qp > 51) { + fprintf(stderr, "alpha_qp must be between 0 and 51\n"); + exit(1); + } + break; + case 3: + lossless_mode = 1; + color_space = BPG_CS_RGB; + format = BPG_FORMAT_444; + bit_depth = 8; + limited_range = 0; + break; + case 4: + limited_range = 1; + break; + case 5: + premultiplied_alpha = 1; + break; + default: + goto show_help; + } + break; + case 'h': + show_help: + help(1); + break; + case 'q': + qp = atoi(optarg); + if (qp < 0 || qp > 51) { + fprintf(stderr, "qp must be between 0 and 51\n"); + exit(1); + } + break; + case 'o': + outfilename = optarg; + break; + case 'f': + if (!strcmp(optarg, "420")) { + format = BPG_FORMAT_420; + } else if (!strcmp(optarg, "422")) { + format = BPG_FORMAT_422; + } else if (!strcmp(optarg, "444")) { + format = BPG_FORMAT_444; + } else { + fprintf(stderr, "Invalid chroma format\n"); + exit(1); + } + break; + case 'c': + if (!strcmp(optarg, "ycbcr")) { + color_space = BPG_CS_YCbCr; + } else if (!strcmp(optarg, "rgb")) { + color_space = BPG_CS_RGB; + format = BPG_FORMAT_444; + } else if (!strcmp(optarg, "ycgco")) { + color_space = BPG_CS_YCgCo; + } else if (!strcmp(optarg, "ycbcr_bt709")) { + color_space = BPG_CS_YCbCr_BT709; + } else if (!strcmp(optarg, "ycbcr_bt2020")) { + color_space = BPG_CS_YCbCr_BT2020; + } else { + fprintf(stderr, "Invalid color space format\n"); + exit(1); + } + break; + case 'm': + compress_level = atoi(optarg); + if (compress_level < 1) + compress_level = 1; + else if (compress_level > 9) + compress_level = 9; + break; + case 'b': + bit_depth = atoi(optarg); + if (bit_depth < 8 || bit_depth > BIT_DEPTH_MAX) { + fprintf(stderr, "Invalid bit depth (range: 8 to %d)\n", + BIT_DEPTH_MAX); + exit(1); + } + break; + case 'v': + verbose++; + break; + case 'e': + for(i = 0; i < HEVC_ENCODER_COUNT; i++) { + if (!strcmp(optarg, hevc_encoder_name[i])) + break; + } + if (i == HEVC_ENCODER_COUNT) { + fprintf(stderr, "Unsupported encoder. Available ones are:"); + for(i = 0; i < HEVC_ENCODER_COUNT; i++) { + fprintf(stderr, " %s", hevc_encoder_name[i]); + } + fprintf(stderr, "\n"); + exit(1); + } + encoder_type = i; + break; + default: + exit(1); + } + } + + if (optind >= argc) + help(0); + infilename = argv[optind]; + + f = fopen(infilename, "rb"); + if (!f) { + perror(infilename); + exit(1); + } + { + uint8_t buf[8]; + if (fread(buf, 1, 8, f) == 8 && + png_sig_cmp(buf, 0, 8) == 0) + is_png = 1; + else + is_png = 0; + fseek(f, 0, SEEK_SET); + } + + if (is_png) { + img = read_png(&md, f, color_space, bit_depth, limited_range, + premultiplied_alpha); + } else { + img = read_jpeg(&md, f, bit_depth); + } + if (!img) { + fprintf(stderr, "Could not read '%s'\n", infilename); + } + fclose(f); + + if (!keep_metadata && md) { + bpg_md_free(md); + md = NULL; + } + + /* extract the alpha plane */ + if (img->has_alpha) { + int c_idx; + + img_alpha = malloc(sizeof(Image)); + memset(img_alpha, 0, sizeof(*img_alpha)); + if (img->format == BPG_FORMAT_GRAY) + c_idx = 1; + else + c_idx = 3; + + img_alpha->w = img->w; + img_alpha->h = img->h; + img_alpha->format = BPG_FORMAT_GRAY; + img_alpha->has_alpha = 0; + img_alpha->color_space = BPG_CS_YCbCr; + img_alpha->bit_depth = bit_depth; + img_alpha->pixel_shift = img->pixel_shift; + img_alpha->data[0] = img->data[c_idx]; + img_alpha->linesize[0] = img->linesize[c_idx]; + + img->data[c_idx] = NULL; + img->has_alpha = 0; + } else { + img_alpha = NULL; + } + + if (img->format == BPG_FORMAT_444) { + if (format == BPG_FORMAT_420) { + if (image_ycc444_to_ycc420(img) != 0) + goto error_convert; + } else if (format == BPG_FORMAT_422) { + if (image_ycc444_to_ycc422(img) != 0) { + error_convert: + fprintf(stderr, "Cannot convert image\n"); + exit(1); + } + } + } + + cb_size = 8; /* XXX: should make it configurable. We assume the + HEVC encoder uses the same value */ + width = img->w; + height = img->h; + image_pad(img, cb_size); + if (img_alpha) + image_pad(img_alpha, cb_size); + + /* convert to the allocated pixel width to 8 bit if needed by the + HEVC encoder */ + if (img->bit_depth == 8) { + image_convert16to8(img); + if (img_alpha) + image_convert16to8(img_alpha); + } + + memset(p, 0, sizeof(*p)); + p->qp = qp; + p->lossless = lossless_mode; + p->sei_decoded_picture_hash = sei_decoded_picture_hash; + p->compress_level = compress_level; + p->verbose = verbose; + out_buf_len = hevc_encode_picture2(&out_buf, img, p, encoder_type); + if (out_buf_len < 0) { + fprintf(stderr, "Error while encoding picture\n"); + exit(1); + } + + alpha_buf = NULL; + alpha_buf_len = 0; + if (img_alpha) { + memset(p, 0, sizeof(*p)); + if (alpha_qp < 0) + p->qp = qp; + else + p->qp = alpha_qp; + p->lossless = lossless_mode; + p->sei_decoded_picture_hash = sei_decoded_picture_hash; + p->compress_level = compress_level; + p->verbose = verbose; + + alpha_buf_len = hevc_encode_picture2(&alpha_buf, img_alpha, p, encoder_type); + if (alpha_buf_len < 0) { + fprintf(stderr, "Error while encoding picture (alpha plane)\n"); + exit(1); + } + } + + /* prepare the extension data */ + extension_buf = NULL; + extension_buf_len = 0; + if (md) { + BPGMetaData *md1; + int max_len; + uint8_t *q; + + max_len = 0; + for(md1 = md; md1 != NULL; md1 = md1->next) { + max_len += md1->buf_len + 5 * 2; + } + extension_buf = malloc(max_len); + q = extension_buf; + for(md1 = md; md1 != NULL; md1 = md1->next) { + put_ue(&q, md1->tag); + put_ue(&q, md1->buf_len); + memcpy(q, md1->buf, md1->buf_len); + q += md1->buf_len; + } + extension_buf_len = q - extension_buf; + + bpg_md_free(md); + } + + f = fopen(outfilename, "wb"); + if (!f) { + perror(outfilename); + exit(1); + } + + { + uint8_t img_header[128], *q; + int v, has_alpha, has_extension, alpha2_flag, alpha1_flag; + + has_alpha = (img_alpha != NULL); + has_extension = (extension_buf_len > 0); + + + if (has_alpha) { + if (img->has_w_plane) { + alpha1_flag = 0; + alpha2_flag = 1; + } else { + alpha1_flag = 1; + alpha2_flag = img->premultiplied_alpha; + } + } else { + alpha1_flag = 0; + alpha2_flag = 0; + } + + q = img_header; + *q++ = (IMAGE_HEADER_MAGIC >> 24) & 0xff; + *q++ = (IMAGE_HEADER_MAGIC >> 16) & 0xff; + *q++ = (IMAGE_HEADER_MAGIC >> 8) & 0xff; + *q++ = (IMAGE_HEADER_MAGIC >> 0) & 0xff; + v = (img->format << 5) | (alpha1_flag << 4) | (img->bit_depth - 8); + *q++ = v; + v = (img->color_space << 4) | (has_extension << 3) | + (alpha2_flag << 2) | (img->limited_range << 1); + *q++ = v; + put_ue(&q, width); + put_ue(&q, height); + + put_ue(&q, out_buf_len); + if (has_extension) { + put_ue(&q, extension_buf_len); /* extension data length */ + } + if (has_alpha) { + put_ue(&q, alpha_buf_len); + } + + fwrite(img_header, 1, q - img_header, f); + + if (has_extension) { + if (fwrite(extension_buf, 1, extension_buf_len, f) != extension_buf_len) { + fprintf(stderr, "Error while writing extension data\n"); + exit(1); + } + free(extension_buf); + } + + /* HEVC YUV/RGB data */ + if (fwrite(out_buf, 1, out_buf_len, f) != out_buf_len) { + fprintf(stderr, "Error while writing HEVC image planes\n"); + exit(1); + } + free(out_buf); + + if (has_alpha) { + /* alpha data */ + if (fwrite(alpha_buf, 1, alpha_buf_len, f) != alpha_buf_len) { + fprintf(stderr, "Error while writing HEVC alpha plane\n"); + exit(1); + } + free(alpha_buf); + } + } + + fclose(f); + + image_free(img); + if (img_alpha) + image_free(img_alpha); + + return 0; +} diff --git a/bpgenc.h b/bpgenc.h new file mode 100644 index 0000000..2994f8d --- /dev/null +++ b/bpgenc.h @@ -0,0 +1,61 @@ +/* + * BPG encoder + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "libbpg.h" + +typedef struct { + int w, h; + BPGImageFormatEnum format; + uint8_t has_alpha; + uint8_t has_w_plane; + uint8_t limited_range; + uint8_t premultiplied_alpha; + BPGColorSpaceEnum color_space; + uint8_t bit_depth; + uint8_t pixel_shift; /* (1 << pixel_shift) bytes per pixel */ + uint8_t *data[4]; + int linesize[4]; +} Image; + +typedef struct { + int qp; /* quantizer 0-51 */ + int lossless; /* 0-1 lossless mode */ + int sei_decoded_picture_hash; /* 0=no hash, 1=MD5 hash */ + int compress_level; /* 1-9 */ + int verbose; +} HEVCEncodeParams; + +int x265_encode_picture(uint8_t **pbuf, Image *img, + const HEVCEncodeParams *params); +int jctvc_encode_picture(uint8_t **pbuf, Image *img, + const HEVCEncodeParams *params); +void save_yuv(Image *img, const char *filename); + +#ifdef __cplusplus +} +#endif + diff --git a/config.h b/config.h new file mode 100644 index 0000000..8df8621 --- /dev/null +++ b/config.h @@ -0,0 +1,1832 @@ +/* Automatically generated by configure - do not modify! */ +#ifndef FFMPEG_CONFIG_H +#define FFMPEG_CONFIG_H +#define FFMPEG_CONFIGURATION "--disable-asm --enable-small --disable-pthreads --disable-everything --enable-decoder=hevc --enable-demuxer=hevc --enable-protocol=file --disable-ffserver --disable-ffprobe --disable-doc --enable-parser=hevc" +#define FFMPEG_LICENSE "LGPL version 2.1 or later" +#define CONFIG_THIS_YEAR 2014 +#define FFMPEG_DATADIR "/usr/local/share/ffmpeg" +#define AVCONV_DATADIR "/usr/local/share/ffmpeg" +#define CC_IDENT "gcc 4.7.2 (GCC) 20120921 (Red Hat 4.7.2-2)" +#define av_restrict restrict +#define EXTERN_PREFIX "" +#define EXTERN_ASM +#define BUILDSUF "" +#define SLIBSUF ".so" +#define HAVE_MMX2 HAVE_MMXEXT +#define SWS_MAX_FILTER_SIZE 256 +#define ARCH_AARCH64 0 +#define ARCH_ALPHA 0 +#define ARCH_ARM 0 +#define ARCH_AVR32 0 +#define ARCH_AVR32_AP 0 +#define ARCH_AVR32_UC 0 +#define ARCH_BFIN 0 +#define ARCH_IA64 0 +#define ARCH_M68K 0 +#define ARCH_MIPS 0 +#define ARCH_MIPS64 0 +#define ARCH_PARISC 0 +#define ARCH_PPC 0 +#define ARCH_PPC64 0 +#define ARCH_S390 0 +#define ARCH_SH4 0 +#define ARCH_SPARC 0 +#define ARCH_SPARC64 0 +#define ARCH_TILEGX 0 +#define ARCH_TILEPRO 0 +#define ARCH_TOMI 0 +#define ARCH_X86 0 +#define ARCH_X86_32 0 +#define ARCH_X86_64 0 +#define HAVE_ARMV5TE 0 +#define HAVE_ARMV6 0 +#define HAVE_ARMV6T2 0 +#define HAVE_ARMV8 0 +#define HAVE_NEON 0 +#define HAVE_VFP 0 +#define HAVE_VFPV3 0 +#define HAVE_SETEND 0 +#define HAVE_ALTIVEC 0 +#define HAVE_DCBZL 0 +#define HAVE_LDBRX 0 +#define HAVE_PPC4XX 0 +#define HAVE_VSX 0 +#define HAVE_AMD3DNOW 0 +#define HAVE_AMD3DNOWEXT 0 +#define HAVE_AVX 0 +#define HAVE_AVX2 0 +#define HAVE_FMA3 0 +#define HAVE_FMA4 0 +#define HAVE_MMX 0 +#define HAVE_MMXEXT 0 +#define HAVE_SSE 0 +#define HAVE_SSE2 0 +#define HAVE_SSE3 0 +#define HAVE_SSE4 0 +#define HAVE_SSE42 0 +#define HAVE_SSSE3 0 +#define HAVE_XOP 0 +#define HAVE_CPUNOP 0 +#define HAVE_I686 0 +#define HAVE_MIPSFPU 0 +#define HAVE_MIPS32R2 0 +#define HAVE_MIPSDSPR1 0 +#define HAVE_MIPSDSPR2 0 +#define HAVE_LOONGSON 0 +#define HAVE_ARMV5TE_EXTERNAL 0 +#define HAVE_ARMV6_EXTERNAL 0 +#define HAVE_ARMV6T2_EXTERNAL 0 +#define HAVE_ARMV8_EXTERNAL 0 +#define HAVE_NEON_EXTERNAL 0 +#define HAVE_VFP_EXTERNAL 0 +#define HAVE_VFPV3_EXTERNAL 0 +#define HAVE_SETEND_EXTERNAL 0 +#define HAVE_ALTIVEC_EXTERNAL 0 +#define HAVE_DCBZL_EXTERNAL 0 +#define HAVE_LDBRX_EXTERNAL 0 +#define HAVE_PPC4XX_EXTERNAL 0 +#define HAVE_VSX_EXTERNAL 0 +#define HAVE_AMD3DNOW_EXTERNAL 0 +#define HAVE_AMD3DNOWEXT_EXTERNAL 0 +#define HAVE_AVX_EXTERNAL 0 +#define HAVE_AVX2_EXTERNAL 0 +#define HAVE_FMA3_EXTERNAL 0 +#define HAVE_FMA4_EXTERNAL 0 +#define HAVE_MMX_EXTERNAL 0 +#define HAVE_MMXEXT_EXTERNAL 0 +#define HAVE_SSE_EXTERNAL 0 +#define HAVE_SSE2_EXTERNAL 0 +#define HAVE_SSE3_EXTERNAL 0 +#define HAVE_SSE4_EXTERNAL 0 +#define HAVE_SSE42_EXTERNAL 0 +#define HAVE_SSSE3_EXTERNAL 0 +#define HAVE_XOP_EXTERNAL 0 +#define HAVE_CPUNOP_EXTERNAL 0 +#define HAVE_I686_EXTERNAL 0 +#define HAVE_MIPSFPU_EXTERNAL 0 +#define HAVE_MIPS32R2_EXTERNAL 0 +#define HAVE_MIPSDSPR1_EXTERNAL 0 +#define HAVE_MIPSDSPR2_EXTERNAL 0 +#define HAVE_LOONGSON_EXTERNAL 0 +#define HAVE_ARMV5TE_INLINE 0 +#define HAVE_ARMV6_INLINE 0 +#define HAVE_ARMV6T2_INLINE 0 +#define HAVE_ARMV8_INLINE 0 +#define HAVE_NEON_INLINE 0 +#define HAVE_VFP_INLINE 0 +#define HAVE_VFPV3_INLINE 0 +#define HAVE_SETEND_INLINE 0 +#define HAVE_ALTIVEC_INLINE 0 +#define HAVE_DCBZL_INLINE 0 +#define HAVE_LDBRX_INLINE 0 +#define HAVE_PPC4XX_INLINE 0 +#define HAVE_VSX_INLINE 0 +#define HAVE_AMD3DNOW_INLINE 0 +#define HAVE_AMD3DNOWEXT_INLINE 0 +#define HAVE_AVX_INLINE 0 +#define HAVE_AVX2_INLINE 0 +#define HAVE_FMA3_INLINE 0 +#define HAVE_FMA4_INLINE 0 +#define HAVE_MMX_INLINE 0 +#define HAVE_MMXEXT_INLINE 0 +#define HAVE_SSE_INLINE 0 +#define HAVE_SSE2_INLINE 0 +#define HAVE_SSE3_INLINE 0 +#define HAVE_SSE4_INLINE 0 +#define HAVE_SSE42_INLINE 0 +#define HAVE_SSSE3_INLINE 0 +#define HAVE_XOP_INLINE 0 +#define HAVE_CPUNOP_INLINE 0 +#define HAVE_I686_INLINE 0 +#define HAVE_MIPSFPU_INLINE 0 +#define HAVE_MIPS32R2_INLINE 0 +#define HAVE_MIPSDSPR1_INLINE 0 +#define HAVE_MIPSDSPR2_INLINE 0 +#define HAVE_LOONGSON_INLINE 0 +#define HAVE_ALIGNED_STACK 0 +#define HAVE_FAST_64BIT 0 +#define HAVE_FAST_CLZ 0 +#define HAVE_FAST_CMOV 0 +#define HAVE_LOCAL_ALIGNED_8 1 +#define HAVE_LOCAL_ALIGNED_16 1 +#define HAVE_LOCAL_ALIGNED_32 1 +#define HAVE_SIMD_ALIGN_16 0 +#define HAVE_ATOMICS_GCC 1 +#define HAVE_ATOMICS_SUNCC 0 +#define HAVE_ATOMICS_WIN32 0 +#define HAVE_ATOMIC_CAS_PTR 0 +#define HAVE_ATOMIC_COMPARE_EXCHANGE 1 +#define HAVE_MACHINE_RW_BARRIER 0 +#define HAVE_MEMORYBARRIER 0 +#define HAVE_MM_EMPTY 1 +#define HAVE_RDTSC 0 +#define HAVE_SARESTART 1 +#define HAVE_SYNC_VAL_COMPARE_AND_SWAP 1 +#define HAVE_INLINE_ASM 1 +#define HAVE_SYMVER 1 +#define HAVE_YASM 0 +#define HAVE_BIGENDIAN 0 +#define HAVE_FAST_UNALIGNED 0 +#define HAVE_INCOMPATIBLE_LIBAV_ABI 0 +#define HAVE_ALSA_ASOUNDLIB_H 0 +#define HAVE_ALTIVEC_H 0 +#define HAVE_ARPA_INET_H 1 +#define HAVE_ASM_TYPES_H 1 +#define HAVE_CDIO_PARANOIA_H 0 +#define HAVE_CDIO_PARANOIA_PARANOIA_H 0 +#define HAVE_CL_CL_H 0 +#define HAVE_DEV_BKTR_IOCTL_BT848_H 0 +#define HAVE_DEV_BKTR_IOCTL_METEOR_H 0 +#define HAVE_DEV_IC_BT8XX_H 0 +#define HAVE_DEV_VIDEO_BKTR_IOCTL_BT848_H 0 +#define HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H 0 +#define HAVE_DIRECT_H 0 +#define HAVE_DLFCN_H 1 +#define HAVE_DXVA_H 0 +#define HAVE_ES2_GL_H 0 +#define HAVE_GSM_H 0 +#define HAVE_IO_H 0 +#define HAVE_MACH_MACH_TIME_H 0 +#define HAVE_MACHINE_IOCTL_BT848_H 0 +#define HAVE_MACHINE_IOCTL_METEOR_H 0 +#define HAVE_MALLOC_H 0 +#define HAVE_OPENJPEG_1_5_OPENJPEG_H 0 +#define HAVE_OPENGL_GL3_H 0 +#define HAVE_POLL_H 1 +#define HAVE_SNDIO_H 0 +#define HAVE_SOUNDCARD_H 0 +#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_SOUNDCARD_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_UN_H 1 +#define HAVE_SYS_VIDEOIO_H 0 +#define HAVE_TERMIOS_H 1 +#define HAVE_UDPLITE_H 0 +#define HAVE_UNISTD_H 1 +#define HAVE_WINDOWS_H 0 +#define HAVE_WINSOCK2_H 0 +#define HAVE_INTRINSICS_NEON 0 +#define HAVE_ATANF 1 +#define HAVE_ATAN2F 1 +#define HAVE_CBRT 1 +#define HAVE_CBRTF 1 +#define HAVE_COSF 1 +#define HAVE_EXP2 1 +#define HAVE_EXP2F 1 +#define HAVE_EXPF 1 +#define HAVE_ISINF 1 +#define HAVE_ISNAN 1 +#define HAVE_LDEXPF 1 +#define HAVE_LLRINT 1 +#define HAVE_LLRINTF 1 +#define HAVE_LOG2 1 +#define HAVE_LOG2F 1 +#define HAVE_LOG10F 1 +#define HAVE_LRINT 1 +#define HAVE_LRINTF 1 +#define HAVE_POWF 1 +#define HAVE_RINT 1 +#define HAVE_ROUND 1 +#define HAVE_ROUNDF 1 +#define HAVE_SINF 1 +#define HAVE_TRUNC 1 +#define HAVE_TRUNCF 1 +#define HAVE_ACCESS 1 +#define HAVE_ALIGNED_MALLOC 0 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_CLOSESOCKET 0 +#define HAVE_COMMANDLINETOARGVW 0 +#define HAVE_COTASKMEMFREE 0 +#define HAVE_CRYPTGENRANDOM 0 +#define HAVE_DLOPEN 1 +#define HAVE_FCNTL 1 +#define HAVE_FLT_LIM 1 +#define HAVE_FORK 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETHRTIME 0 +#define HAVE_GETOPT 1 +#define HAVE_GETPROCESSAFFINITYMASK 0 +#define HAVE_GETPROCESSMEMORYINFO 0 +#define HAVE_GETPROCESSTIMES 0 +#define HAVE_GETRUSAGE 1 +#define HAVE_GETSERVBYPORT 1 +#define HAVE_GETSYSTEMTIMEASFILETIME 0 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_GLOB 1 +#define HAVE_GLXGETPROCADDRESS 0 +#define HAVE_GMTIME_R 1 +#define HAVE_INET_ATON 1 +#define HAVE_ISATTY 1 +#define HAVE_JACK_PORT_GET_LATENCY_RANGE 0 +#define HAVE_KBHIT 0 +#define HAVE_LOCALTIME_R 1 +#define HAVE_LZO1X_999_COMPRESS 0 +#define HAVE_MACH_ABSOLUTE_TIME 0 +#define HAVE_MAPVIEWOFFILE 0 +#define HAVE_MEMALIGN 0 +#define HAVE_MKSTEMP 1 +#define HAVE_MMAP 1 +#define HAVE_MPROTECT 1 +#define HAVE_NANOSLEEP 1 +#define HAVE_PEEKNAMEDPIPE 0 +#define HAVE_POSIX_MEMALIGN 0 +#define HAVE_PTHREAD_CANCEL 0 +#define HAVE_SCHED_GETAFFINITY 1 +#define HAVE_SETCONSOLETEXTATTRIBUTE 0 +#define HAVE_SETMODE 0 +#define HAVE_SETRLIMIT 1 +#define HAVE_SLEEP 0 +#define HAVE_STRERROR_R 1 +#define HAVE_SYSCONF 1 +#define HAVE_SYSCTL 1 +#define HAVE_USLEEP 1 +#define HAVE_VIRTUALALLOC 0 +#define HAVE_WGLGETPROCADDRESS 0 +#define HAVE_PTHREADS 0 +#define HAVE_OS2THREADS 0 +#define HAVE_W32THREADS 0 +#define HAVE_AS_DN_DIRECTIVE 0 +#define HAVE_AS_FUNC 0 +#define HAVE_ASM_MOD_Q 0 +#define HAVE_ATTRIBUTE_MAY_ALIAS 1 +#define HAVE_ATTRIBUTE_PACKED 1 +#define HAVE_EBP_AVAILABLE 1 +#define HAVE_EBX_AVAILABLE 1 +#define HAVE_GNU_AS 0 +#define HAVE_GNU_WINDRES 0 +#define HAVE_IBM_ASM 0 +#define HAVE_INLINE_ASM_LABELS 1 +#define HAVE_INLINE_ASM_NONLOCAL_LABELS 1 +#define HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS 1 +#define HAVE_PRAGMA_DEPRECATED 1 +#define HAVE_RSYNC_CONTIMEOUT 1 +#define HAVE_SYMVER_ASM_LABEL 0 +#define HAVE_SYMVER_GNU_ASM 1 +#define HAVE_VFP_ARGS 0 +#define HAVE_XFORM_ASM 0 +#define HAVE_XMM_CLOBBERS 1 +#define HAVE_CONDITION_VARIABLE_PTR 0 +#define HAVE_SOCKLEN_T 1 +#define HAVE_STRUCT_ADDRINFO 1 +#define HAVE_STRUCT_GROUP_SOURCE_REQ 1 +#define HAVE_STRUCT_IP_MREQ_SOURCE 1 +#define HAVE_STRUCT_IPV6_MREQ 1 +#define HAVE_STRUCT_POLLFD 1 +#define HAVE_STRUCT_RUSAGE_RU_MAXRSS 1 +#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE 1 +#define HAVE_STRUCT_SOCKADDR_IN6 1 +#define HAVE_STRUCT_SOCKADDR_SA_LEN 0 +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 +#define HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE 1 +#define HAVE_ATOMICS_NATIVE 1 +#define HAVE_DOS_PATHS 0 +#define HAVE_DXVA2API_COBJ 0 +#define HAVE_DXVA2_LIB 0 +#define HAVE_LIBC_MSVCRT 0 +#define HAVE_LIBDC1394_1 0 +#define HAVE_LIBDC1394_2 0 +#define HAVE_MAKEINFO 1 +#define HAVE_MAKEINFO_HTML 0 +#define HAVE_PERL 1 +#define HAVE_POD2MAN 1 +#define HAVE_SDL 1 +#define HAVE_TEXI2HTML 0 +#define HAVE_THREADS 0 +#define HAVE_VDPAU_X11 0 +#define HAVE_XLIB 1 +#define CONFIG_BSFS 0 +#define CONFIG_DECODERS 1 +#define CONFIG_DEMUXERS 1 +#define CONFIG_ENCODERS 0 +#define CONFIG_FILTERS 0 +#define CONFIG_HWACCELS 0 +#define CONFIG_INDEVS 0 +#define CONFIG_MUXERS 0 +#define CONFIG_OUTDEVS 0 +#define CONFIG_PARSERS 1 +#define CONFIG_PROTOCOLS 1 +#define CONFIG_DOC 0 +#define CONFIG_HTMLPAGES 0 +#define CONFIG_MANPAGES 1 +#define CONFIG_PODPAGES 1 +#define CONFIG_TXTPAGES 1 +#define CONFIG_AVIO_READING_EXAMPLE 1 +#define CONFIG_DECODING_ENCODING_EXAMPLE 1 +#define CONFIG_DEMUXING_DECODING_EXAMPLE 1 +#define CONFIG_EXTRACT_MVS_EXAMPLE 1 +#define CONFIG_FILTER_AUDIO_EXAMPLE 1 +#define CONFIG_FILTERING_AUDIO_EXAMPLE 1 +#define CONFIG_FILTERING_VIDEO_EXAMPLE 1 +#define CONFIG_METADATA_EXAMPLE 1 +#define CONFIG_MUXING_EXAMPLE 1 +#define CONFIG_REMUXING_EXAMPLE 1 +#define CONFIG_RESAMPLING_AUDIO_EXAMPLE 1 +#define CONFIG_SCALING_VIDEO_EXAMPLE 1 +#define CONFIG_TRANSCODE_AAC_EXAMPLE 1 +#define CONFIG_TRANSCODING_EXAMPLE 1 +#define CONFIG_AVISYNTH 0 +#define CONFIG_BZLIB 0 +#define CONFIG_CRYSTALHD 0 +#define CONFIG_DECKLINK 0 +#define CONFIG_FREI0R 0 +#define CONFIG_GNUTLS 0 +#define CONFIG_ICONV 0 +#define CONFIG_LADSPA 0 +#define CONFIG_LIBAACPLUS 0 +#define CONFIG_LIBASS 0 +#define CONFIG_LIBBLURAY 0 +#define CONFIG_LIBBS2B 0 +#define CONFIG_LIBCACA 0 +#define CONFIG_LIBCDIO 0 +#define CONFIG_LIBCELT 0 +#define CONFIG_LIBDC1394 0 +#define CONFIG_LIBFAAC 0 +#define CONFIG_LIBFDK_AAC 0 +#define CONFIG_LIBFLITE 0 +#define CONFIG_LIBFONTCONFIG 0 +#define CONFIG_LIBFREETYPE 0 +#define CONFIG_LIBFRIBIDI 0 +#define CONFIG_LIBGME 0 +#define CONFIG_LIBGSM 0 +#define CONFIG_LIBIEC61883 0 +#define CONFIG_LIBILBC 0 +#define CONFIG_LIBMODPLUG 0 +#define CONFIG_LIBMP3LAME 0 +#define CONFIG_LIBNUT 0 +#define CONFIG_LIBOPENCORE_AMRNB 0 +#define CONFIG_LIBOPENCORE_AMRWB 0 +#define CONFIG_LIBOPENCV 0 +#define CONFIG_LIBOPENJPEG 0 +#define CONFIG_LIBOPUS 0 +#define CONFIG_LIBPULSE 0 +#define CONFIG_LIBQUVI 0 +#define CONFIG_LIBRTMP 0 +#define CONFIG_LIBSCHROEDINGER 0 +#define CONFIG_LIBSHINE 0 +#define CONFIG_LIBSMBCLIENT 0 +#define CONFIG_LIBSOXR 0 +#define CONFIG_LIBSPEEX 0 +#define CONFIG_LIBSSH 0 +#define CONFIG_LIBSTAGEFRIGHT_H264 0 +#define CONFIG_LIBTHEORA 0 +#define CONFIG_LIBTWOLAME 0 +#define CONFIG_LIBUTVIDEO 0 +#define CONFIG_LIBV4L2 0 +#define CONFIG_LIBVIDSTAB 0 +#define CONFIG_LIBVO_AACENC 0 +#define CONFIG_LIBVO_AMRWBENC 0 +#define CONFIG_LIBVORBIS 0 +#define CONFIG_LIBVPX 0 +#define CONFIG_LIBWAVPACK 0 +#define CONFIG_LIBWEBP 0 +#define CONFIG_LIBX264 0 +#define CONFIG_LIBX265 0 +#define CONFIG_LIBXAVS 0 +#define CONFIG_LIBXCB 1 +#define CONFIG_LIBXCB_SHM 1 +#define CONFIG_LIBXCB_XFIXES 1 +#define CONFIG_LIBXVID 0 +#define CONFIG_LIBZMQ 0 +#define CONFIG_LIBZVBI 0 +#define CONFIG_LZMA 0 +#define CONFIG_OPENAL 0 +#define CONFIG_OPENCL 0 +#define CONFIG_OPENGL 0 +#define CONFIG_OPENSSL 0 +#define CONFIG_SDL 1 +#define CONFIG_X11GRAB 0 +#define CONFIG_XLIB 1 +#define CONFIG_ZLIB 0 +#define CONFIG_FTRAPV 0 +#define CONFIG_GRAY 0 +#define CONFIG_HARDCODED_TABLES 0 +#define CONFIG_RUNTIME_CPUDETECT 1 +#define CONFIG_SAFE_BITSTREAM_READER 1 +#define CONFIG_SHARED 0 +#define CONFIG_SMALL 1 +#define CONFIG_STATIC 1 +#define CONFIG_SWSCALE_ALPHA 1 +#define CONFIG_DXVA2 0 +#define CONFIG_VAAPI 0 +#define CONFIG_VDA 0 +#define CONFIG_VDPAU 0 +#define CONFIG_XVMC 1 +#define CONFIG_GPL 0 +#define CONFIG_NONFREE 0 +#define CONFIG_VERSION3 0 +#define CONFIG_AVCODEC 1 +#define CONFIG_AVDEVICE 1 +#define CONFIG_AVFILTER 1 +#define CONFIG_AVFORMAT 1 +#define CONFIG_AVRESAMPLE 0 +#define CONFIG_AVUTIL 1 +#define CONFIG_POSTPROC 0 +#define CONFIG_SWRESAMPLE 1 +#define CONFIG_SWSCALE 1 +#define CONFIG_FFPLAY 1 +#define CONFIG_FFPROBE 0 +#define CONFIG_FFSERVER 0 +#define CONFIG_FFMPEG 1 +#define CONFIG_DCT 0 +#define CONFIG_DWT 0 +#define CONFIG_ERROR_RESILIENCE 0 +#define CONFIG_FAAN 1 +#define CONFIG_FAST_UNALIGNED 0 +#define CONFIG_FFT 1 +#define CONFIG_LSP 0 +#define CONFIG_LZO 0 +#define CONFIG_MDCT 0 +#define CONFIG_PIXELUTILS 0 +#define CONFIG_NETWORK 0 +#define CONFIG_RDFT 1 +#define CONFIG_FONTCONFIG 0 +#define CONFIG_INCOMPATIBLE_LIBAV_ABI 0 +#define CONFIG_MEMALIGN_HACK 0 +#define CONFIG_MEMORY_POISONING 0 +#define CONFIG_NEON_CLOBBER_TEST 0 +#define CONFIG_PIC 0 +#define CONFIG_POD2MAN 1 +#define CONFIG_RAISE_MAJOR 0 +#define CONFIG_THUMB 0 +#define CONFIG_XMM_CLOBBER_TEST 0 +#define CONFIG_AANDCTTABLES 0 +#define CONFIG_AC3DSP 0 +#define CONFIG_AUDIO_FRAME_QUEUE 0 +#define CONFIG_AUDIODSP 0 +#define CONFIG_BLOCKDSP 0 +#define CONFIG_BSWAPDSP 1 +#define CONFIG_CABAC 1 +#define CONFIG_DVPROFILE 0 +#define CONFIG_EXIF 0 +#define CONFIG_FAANDCT 0 +#define CONFIG_FAANIDCT 0 +#define CONFIG_FDCTDSP 0 +#define CONFIG_FRAME_THREAD_ENCODER 0 +#define CONFIG_GCRYPT 0 +#define CONFIG_GOLOMB 1 +#define CONFIG_GPLV3 0 +#define CONFIG_H263DSP 0 +#define CONFIG_H264CHROMA 0 +#define CONFIG_H264DSP 0 +#define CONFIG_H264PRED 0 +#define CONFIG_H264QPEL 0 +#define CONFIG_HPELDSP 0 +#define CONFIG_HUFFMAN 0 +#define CONFIG_HUFFYUVDSP 0 +#define CONFIG_HUFFYUVENCDSP 0 +#define CONFIG_IDCTDSP 0 +#define CONFIG_IIRFILTER 0 +#define CONFIG_INTRAX8 0 +#define CONFIG_LGPLV3 0 +#define CONFIG_LLAUDDSP 0 +#define CONFIG_LLVIDDSP 0 +#define CONFIG_LPC 0 +#define CONFIG_ME_CMP 0 +#define CONFIG_MPEG_ER 0 +#define CONFIG_MPEGAUDIO 0 +#define CONFIG_MPEGAUDIODSP 0 +#define CONFIG_MPEGVIDEO 0 +#define CONFIG_MPEGVIDEOENC 0 +#define CONFIG_NETTLE 0 +#define CONFIG_PIXBLOCKDSP 0 +#define CONFIG_QPELDSP 0 +#define CONFIG_RANGECODER 0 +#define CONFIG_RIFFDEC 0 +#define CONFIG_RIFFENC 0 +#define CONFIG_RTPDEC 0 +#define CONFIG_RTPENC_CHAIN 0 +#define CONFIG_SINEWIN 0 +#define CONFIG_STARTCODE 0 +#define CONFIG_TPELDSP 0 +#define CONFIG_VIDEODSP 1 +#define CONFIG_VP3DSP 0 +#define CONFIG_WMA_FREQS 0 +#define CONFIG_AAC_ADTSTOASC_BSF 0 +#define CONFIG_CHOMP_BSF 0 +#define CONFIG_DUMP_EXTRADATA_BSF 0 +#define CONFIG_H264_MP4TOANNEXB_BSF 0 +#define CONFIG_IMX_DUMP_HEADER_BSF 0 +#define CONFIG_MJPEG2JPEG_BSF 0 +#define CONFIG_MJPEGA_DUMP_HEADER_BSF 0 +#define CONFIG_MP3_HEADER_DECOMPRESS_BSF 0 +#define CONFIG_MOV2TEXTSUB_BSF 0 +#define CONFIG_NOISE_BSF 0 +#define CONFIG_REMOVE_EXTRADATA_BSF 0 +#define CONFIG_TEXT2MOVSUB_BSF 0 +#define CONFIG_AASC_DECODER 0 +#define CONFIG_AIC_DECODER 0 +#define CONFIG_ALIAS_PIX_DECODER 0 +#define CONFIG_AMV_DECODER 0 +#define CONFIG_ANM_DECODER 0 +#define CONFIG_ANSI_DECODER 0 +#define CONFIG_ASV1_DECODER 0 +#define CONFIG_ASV2_DECODER 0 +#define CONFIG_AURA_DECODER 0 +#define CONFIG_AURA2_DECODER 0 +#define CONFIG_AVRP_DECODER 0 +#define CONFIG_AVRN_DECODER 0 +#define CONFIG_AVS_DECODER 0 +#define CONFIG_AVUI_DECODER 0 +#define CONFIG_AYUV_DECODER 0 +#define CONFIG_BETHSOFTVID_DECODER 0 +#define CONFIG_BFI_DECODER 0 +#define CONFIG_BINK_DECODER 0 +#define CONFIG_BMP_DECODER 0 +#define CONFIG_BMV_VIDEO_DECODER 0 +#define CONFIG_BRENDER_PIX_DECODER 0 +#define CONFIG_C93_DECODER 0 +#define CONFIG_CAVS_DECODER 0 +#define CONFIG_CDGRAPHICS_DECODER 0 +#define CONFIG_CDXL_DECODER 0 +#define CONFIG_CINEPAK_DECODER 0 +#define CONFIG_CLJR_DECODER 0 +#define CONFIG_CLLC_DECODER 0 +#define CONFIG_COMFORTNOISE_DECODER 0 +#define CONFIG_CPIA_DECODER 0 +#define CONFIG_CSCD_DECODER 0 +#define CONFIG_CYUV_DECODER 0 +#define CONFIG_DFA_DECODER 0 +#define CONFIG_DIRAC_DECODER 0 +#define CONFIG_DNXHD_DECODER 0 +#define CONFIG_DPX_DECODER 0 +#define CONFIG_DSICINVIDEO_DECODER 0 +#define CONFIG_DVVIDEO_DECODER 0 +#define CONFIG_DXA_DECODER 0 +#define CONFIG_DXTORY_DECODER 0 +#define CONFIG_EACMV_DECODER 0 +#define CONFIG_EAMAD_DECODER 0 +#define CONFIG_EATGQ_DECODER 0 +#define CONFIG_EATGV_DECODER 0 +#define CONFIG_EATQI_DECODER 0 +#define CONFIG_EIGHTBPS_DECODER 0 +#define CONFIG_EIGHTSVX_EXP_DECODER 0 +#define CONFIG_EIGHTSVX_FIB_DECODER 0 +#define CONFIG_ESCAPE124_DECODER 0 +#define CONFIG_ESCAPE130_DECODER 0 +#define CONFIG_EXR_DECODER 0 +#define CONFIG_FFV1_DECODER 0 +#define CONFIG_FFVHUFF_DECODER 0 +#define CONFIG_FIC_DECODER 0 +#define CONFIG_FLASHSV_DECODER 0 +#define CONFIG_FLASHSV2_DECODER 0 +#define CONFIG_FLIC_DECODER 0 +#define CONFIG_FLV_DECODER 0 +#define CONFIG_FOURXM_DECODER 0 +#define CONFIG_FRAPS_DECODER 0 +#define CONFIG_FRWU_DECODER 0 +#define CONFIG_G2M_DECODER 0 +#define CONFIG_GIF_DECODER 0 +#define CONFIG_H261_DECODER 0 +#define CONFIG_H263_DECODER 0 +#define CONFIG_H263I_DECODER 0 +#define CONFIG_H263P_DECODER 0 +#define CONFIG_H264_DECODER 0 +#define CONFIG_H264_CRYSTALHD_DECODER 0 +#define CONFIG_H264_VDA_DECODER 0 +#define CONFIG_H264_VDPAU_DECODER 0 +#define CONFIG_HEVC_DECODER 1 +#define CONFIG_HNM4_VIDEO_DECODER 0 +#define CONFIG_HUFFYUV_DECODER 0 +#define CONFIG_IDCIN_DECODER 0 +#define CONFIG_IFF_BYTERUN1_DECODER 0 +#define CONFIG_IFF_ILBM_DECODER 0 +#define CONFIG_INDEO2_DECODER 0 +#define CONFIG_INDEO3_DECODER 0 +#define CONFIG_INDEO4_DECODER 0 +#define CONFIG_INDEO5_DECODER 0 +#define CONFIG_INTERPLAY_VIDEO_DECODER 0 +#define CONFIG_JPEG2000_DECODER 0 +#define CONFIG_JPEGLS_DECODER 0 +#define CONFIG_JV_DECODER 0 +#define CONFIG_KGV1_DECODER 0 +#define CONFIG_KMVC_DECODER 0 +#define CONFIG_LAGARITH_DECODER 0 +#define CONFIG_LOCO_DECODER 0 +#define CONFIG_MDEC_DECODER 0 +#define CONFIG_MIMIC_DECODER 0 +#define CONFIG_MJPEG_DECODER 0 +#define CONFIG_MJPEGB_DECODER 0 +#define CONFIG_MMVIDEO_DECODER 0 +#define CONFIG_MOTIONPIXELS_DECODER 0 +#define CONFIG_MPEG_XVMC_DECODER 0 +#define CONFIG_MPEG1VIDEO_DECODER 0 +#define CONFIG_MPEG2VIDEO_DECODER 0 +#define CONFIG_MPEG4_DECODER 0 +#define CONFIG_MPEG4_CRYSTALHD_DECODER 0 +#define CONFIG_MPEG4_VDPAU_DECODER 0 +#define CONFIG_MPEGVIDEO_DECODER 0 +#define CONFIG_MPEG_VDPAU_DECODER 0 +#define CONFIG_MPEG1_VDPAU_DECODER 0 +#define CONFIG_MPEG2_CRYSTALHD_DECODER 0 +#define CONFIG_MSA1_DECODER 0 +#define CONFIG_MSMPEG4_CRYSTALHD_DECODER 0 +#define CONFIG_MSMPEG4V1_DECODER 0 +#define CONFIG_MSMPEG4V2_DECODER 0 +#define CONFIG_MSMPEG4V3_DECODER 0 +#define CONFIG_MSRLE_DECODER 0 +#define CONFIG_MSS1_DECODER 0 +#define CONFIG_MSS2_DECODER 0 +#define CONFIG_MSVIDEO1_DECODER 0 +#define CONFIG_MSZH_DECODER 0 +#define CONFIG_MTS2_DECODER 0 +#define CONFIG_MVC1_DECODER 0 +#define CONFIG_MVC2_DECODER 0 +#define CONFIG_MXPEG_DECODER 0 +#define CONFIG_NUV_DECODER 0 +#define CONFIG_PAF_VIDEO_DECODER 0 +#define CONFIG_PAM_DECODER 0 +#define CONFIG_PBM_DECODER 0 +#define CONFIG_PCX_DECODER 0 +#define CONFIG_PGM_DECODER 0 +#define CONFIG_PGMYUV_DECODER 0 +#define CONFIG_PICTOR_DECODER 0 +#define CONFIG_PNG_DECODER 0 +#define CONFIG_PPM_DECODER 0 +#define CONFIG_PRORES_DECODER 0 +#define CONFIG_PRORES_LGPL_DECODER 0 +#define CONFIG_PTX_DECODER 0 +#define CONFIG_QDRAW_DECODER 0 +#define CONFIG_QPEG_DECODER 0 +#define CONFIG_QTRLE_DECODER 0 +#define CONFIG_R10K_DECODER 0 +#define CONFIG_R210_DECODER 0 +#define CONFIG_RAWVIDEO_DECODER 0 +#define CONFIG_RL2_DECODER 0 +#define CONFIG_ROQ_DECODER 0 +#define CONFIG_RPZA_DECODER 0 +#define CONFIG_RV10_DECODER 0 +#define CONFIG_RV20_DECODER 0 +#define CONFIG_RV30_DECODER 0 +#define CONFIG_RV40_DECODER 0 +#define CONFIG_S302M_DECODER 0 +#define CONFIG_SANM_DECODER 0 +#define CONFIG_SGI_DECODER 0 +#define CONFIG_SGIRLE_DECODER 0 +#define CONFIG_SMACKER_DECODER 0 +#define CONFIG_SMC_DECODER 0 +#define CONFIG_SMVJPEG_DECODER 0 +#define CONFIG_SNOW_DECODER 0 +#define CONFIG_SP5X_DECODER 0 +#define CONFIG_SUNRAST_DECODER 0 +#define CONFIG_SVQ1_DECODER 0 +#define CONFIG_SVQ3_DECODER 0 +#define CONFIG_TARGA_DECODER 0 +#define CONFIG_TARGA_Y216_DECODER 0 +#define CONFIG_THEORA_DECODER 0 +#define CONFIG_THP_DECODER 0 +#define CONFIG_TIERTEXSEQVIDEO_DECODER 0 +#define CONFIG_TIFF_DECODER 0 +#define CONFIG_TMV_DECODER 0 +#define CONFIG_TRUEMOTION1_DECODER 0 +#define CONFIG_TRUEMOTION2_DECODER 0 +#define CONFIG_TSCC_DECODER 0 +#define CONFIG_TSCC2_DECODER 0 +#define CONFIG_TXD_DECODER 0 +#define CONFIG_ULTI_DECODER 0 +#define CONFIG_UTVIDEO_DECODER 0 +#define CONFIG_V210_DECODER 0 +#define CONFIG_V210X_DECODER 0 +#define CONFIG_V308_DECODER 0 +#define CONFIG_V408_DECODER 0 +#define CONFIG_V410_DECODER 0 +#define CONFIG_VB_DECODER 0 +#define CONFIG_VBLE_DECODER 0 +#define CONFIG_VC1_DECODER 0 +#define CONFIG_VC1_CRYSTALHD_DECODER 0 +#define CONFIG_VC1_VDPAU_DECODER 0 +#define CONFIG_VC1IMAGE_DECODER 0 +#define CONFIG_VCR1_DECODER 0 +#define CONFIG_VMDVIDEO_DECODER 0 +#define CONFIG_VMNC_DECODER 0 +#define CONFIG_VP3_DECODER 0 +#define CONFIG_VP5_DECODER 0 +#define CONFIG_VP6_DECODER 0 +#define CONFIG_VP6A_DECODER 0 +#define CONFIG_VP6F_DECODER 0 +#define CONFIG_VP7_DECODER 0 +#define CONFIG_VP8_DECODER 0 +#define CONFIG_VP9_DECODER 0 +#define CONFIG_VQA_DECODER 0 +#define CONFIG_WEBP_DECODER 0 +#define CONFIG_WMV1_DECODER 0 +#define CONFIG_WMV2_DECODER 0 +#define CONFIG_WMV3_DECODER 0 +#define CONFIG_WMV3_CRYSTALHD_DECODER 0 +#define CONFIG_WMV3_VDPAU_DECODER 0 +#define CONFIG_WMV3IMAGE_DECODER 0 +#define CONFIG_WNV1_DECODER 0 +#define CONFIG_XAN_WC3_DECODER 0 +#define CONFIG_XAN_WC4_DECODER 0 +#define CONFIG_XBM_DECODER 0 +#define CONFIG_XFACE_DECODER 0 +#define CONFIG_XL_DECODER 0 +#define CONFIG_XWD_DECODER 0 +#define CONFIG_Y41P_DECODER 0 +#define CONFIG_YOP_DECODER 0 +#define CONFIG_YUV4_DECODER 0 +#define CONFIG_ZERO12V_DECODER 0 +#define CONFIG_ZEROCODEC_DECODER 0 +#define CONFIG_ZLIB_DECODER 0 +#define CONFIG_ZMBV_DECODER 0 +#define CONFIG_AAC_DECODER 0 +#define CONFIG_AAC_LATM_DECODER 0 +#define CONFIG_AC3_DECODER 0 +#define CONFIG_AC3_FIXED_DECODER 0 +#define CONFIG_ALAC_DECODER 0 +#define CONFIG_ALS_DECODER 0 +#define CONFIG_AMRNB_DECODER 0 +#define CONFIG_AMRWB_DECODER 0 +#define CONFIG_APE_DECODER 0 +#define CONFIG_ATRAC1_DECODER 0 +#define CONFIG_ATRAC3_DECODER 0 +#define CONFIG_ATRAC3P_DECODER 0 +#define CONFIG_BINKAUDIO_DCT_DECODER 0 +#define CONFIG_BINKAUDIO_RDFT_DECODER 0 +#define CONFIG_BMV_AUDIO_DECODER 0 +#define CONFIG_COOK_DECODER 0 +#define CONFIG_DCA_DECODER 0 +#define CONFIG_DSD_LSBF_DECODER 0 +#define CONFIG_DSD_MSBF_DECODER 0 +#define CONFIG_DSD_LSBF_PLANAR_DECODER 0 +#define CONFIG_DSD_MSBF_PLANAR_DECODER 0 +#define CONFIG_DSICINAUDIO_DECODER 0 +#define CONFIG_EAC3_DECODER 0 +#define CONFIG_EVRC_DECODER 0 +#define CONFIG_FFWAVESYNTH_DECODER 0 +#define CONFIG_FLAC_DECODER 0 +#define CONFIG_G723_1_DECODER 0 +#define CONFIG_G729_DECODER 0 +#define CONFIG_GSM_DECODER 0 +#define CONFIG_GSM_MS_DECODER 0 +#define CONFIG_IAC_DECODER 0 +#define CONFIG_IMC_DECODER 0 +#define CONFIG_MACE3_DECODER 0 +#define CONFIG_MACE6_DECODER 0 +#define CONFIG_METASOUND_DECODER 0 +#define CONFIG_MLP_DECODER 0 +#define CONFIG_MP1_DECODER 0 +#define CONFIG_MP1FLOAT_DECODER 0 +#define CONFIG_MP2_DECODER 0 +#define CONFIG_MP2FLOAT_DECODER 0 +#define CONFIG_MP3_DECODER 0 +#define CONFIG_MP3FLOAT_DECODER 0 +#define CONFIG_MP3ADU_DECODER 0 +#define CONFIG_MP3ADUFLOAT_DECODER 0 +#define CONFIG_MP3ON4_DECODER 0 +#define CONFIG_MP3ON4FLOAT_DECODER 0 +#define CONFIG_MPC7_DECODER 0 +#define CONFIG_MPC8_DECODER 0 +#define CONFIG_NELLYMOSER_DECODER 0 +#define CONFIG_ON2AVC_DECODER 0 +#define CONFIG_OPUS_DECODER 0 +#define CONFIG_PAF_AUDIO_DECODER 0 +#define CONFIG_QCELP_DECODER 0 +#define CONFIG_QDM2_DECODER 0 +#define CONFIG_RA_144_DECODER 0 +#define CONFIG_RA_288_DECODER 0 +#define CONFIG_RALF_DECODER 0 +#define CONFIG_SHORTEN_DECODER 0 +#define CONFIG_SIPR_DECODER 0 +#define CONFIG_SMACKAUD_DECODER 0 +#define CONFIG_SONIC_DECODER 0 +#define CONFIG_TAK_DECODER 0 +#define CONFIG_TRUEHD_DECODER 0 +#define CONFIG_TRUESPEECH_DECODER 0 +#define CONFIG_TTA_DECODER 0 +#define CONFIG_TWINVQ_DECODER 0 +#define CONFIG_VMDAUDIO_DECODER 0 +#define CONFIG_VORBIS_DECODER 0 +#define CONFIG_WAVPACK_DECODER 0 +#define CONFIG_WMALOSSLESS_DECODER 0 +#define CONFIG_WMAPRO_DECODER 0 +#define CONFIG_WMAV1_DECODER 0 +#define CONFIG_WMAV2_DECODER 0 +#define CONFIG_WMAVOICE_DECODER 0 +#define CONFIG_WS_SND1_DECODER 0 +#define CONFIG_PCM_ALAW_DECODER 0 +#define CONFIG_PCM_BLURAY_DECODER 0 +#define CONFIG_PCM_DVD_DECODER 0 +#define CONFIG_PCM_F32BE_DECODER 0 +#define CONFIG_PCM_F32LE_DECODER 0 +#define CONFIG_PCM_F64BE_DECODER 0 +#define CONFIG_PCM_F64LE_DECODER 0 +#define CONFIG_PCM_LXF_DECODER 0 +#define CONFIG_PCM_MULAW_DECODER 0 +#define CONFIG_PCM_S8_DECODER 0 +#define CONFIG_PCM_S8_PLANAR_DECODER 0 +#define CONFIG_PCM_S16BE_DECODER 0 +#define CONFIG_PCM_S16BE_PLANAR_DECODER 0 +#define CONFIG_PCM_S16LE_DECODER 0 +#define CONFIG_PCM_S16LE_PLANAR_DECODER 0 +#define CONFIG_PCM_S24BE_DECODER 0 +#define CONFIG_PCM_S24DAUD_DECODER 0 +#define CONFIG_PCM_S24LE_DECODER 0 +#define CONFIG_PCM_S24LE_PLANAR_DECODER 0 +#define CONFIG_PCM_S32BE_DECODER 0 +#define CONFIG_PCM_S32LE_DECODER 0 +#define CONFIG_PCM_S32LE_PLANAR_DECODER 0 +#define CONFIG_PCM_U8_DECODER 0 +#define CONFIG_PCM_U16BE_DECODER 0 +#define CONFIG_PCM_U16LE_DECODER 0 +#define CONFIG_PCM_U24BE_DECODER 0 +#define CONFIG_PCM_U24LE_DECODER 0 +#define CONFIG_PCM_U32BE_DECODER 0 +#define CONFIG_PCM_U32LE_DECODER 0 +#define CONFIG_PCM_ZORK_DECODER 0 +#define CONFIG_INTERPLAY_DPCM_DECODER 0 +#define CONFIG_ROQ_DPCM_DECODER 0 +#define CONFIG_SOL_DPCM_DECODER 0 +#define CONFIG_XAN_DPCM_DECODER 0 +#define CONFIG_ADPCM_4XM_DECODER 0 +#define CONFIG_ADPCM_ADX_DECODER 0 +#define CONFIG_ADPCM_AFC_DECODER 0 +#define CONFIG_ADPCM_CT_DECODER 0 +#define CONFIG_ADPCM_DTK_DECODER 0 +#define CONFIG_ADPCM_EA_DECODER 0 +#define CONFIG_ADPCM_EA_MAXIS_XA_DECODER 0 +#define CONFIG_ADPCM_EA_R1_DECODER 0 +#define CONFIG_ADPCM_EA_R2_DECODER 0 +#define CONFIG_ADPCM_EA_R3_DECODER 0 +#define CONFIG_ADPCM_EA_XAS_DECODER 0 +#define CONFIG_ADPCM_G722_DECODER 0 +#define CONFIG_ADPCM_G726_DECODER 0 +#define CONFIG_ADPCM_G726LE_DECODER 0 +#define CONFIG_ADPCM_IMA_AMV_DECODER 0 +#define CONFIG_ADPCM_IMA_APC_DECODER 0 +#define CONFIG_ADPCM_IMA_DK3_DECODER 0 +#define CONFIG_ADPCM_IMA_DK4_DECODER 0 +#define CONFIG_ADPCM_IMA_EA_EACS_DECODER 0 +#define CONFIG_ADPCM_IMA_EA_SEAD_DECODER 0 +#define CONFIG_ADPCM_IMA_ISS_DECODER 0 +#define CONFIG_ADPCM_IMA_OKI_DECODER 0 +#define CONFIG_ADPCM_IMA_QT_DECODER 0 +#define CONFIG_ADPCM_IMA_RAD_DECODER 0 +#define CONFIG_ADPCM_IMA_SMJPEG_DECODER 0 +#define CONFIG_ADPCM_IMA_WAV_DECODER 0 +#define CONFIG_ADPCM_IMA_WS_DECODER 0 +#define CONFIG_ADPCM_MS_DECODER 0 +#define CONFIG_ADPCM_SBPRO_2_DECODER 0 +#define CONFIG_ADPCM_SBPRO_3_DECODER 0 +#define CONFIG_ADPCM_SBPRO_4_DECODER 0 +#define CONFIG_ADPCM_SWF_DECODER 0 +#define CONFIG_ADPCM_THP_DECODER 0 +#define CONFIG_ADPCM_VIMA_DECODER 0 +#define CONFIG_ADPCM_XA_DECODER 0 +#define CONFIG_ADPCM_YAMAHA_DECODER 0 +#define CONFIG_VIMA_DECODER 0 +#define CONFIG_SSA_DECODER 0 +#define CONFIG_ASS_DECODER 0 +#define CONFIG_DVBSUB_DECODER 0 +#define CONFIG_DVDSUB_DECODER 0 +#define CONFIG_JACOSUB_DECODER 0 +#define CONFIG_MICRODVD_DECODER 0 +#define CONFIG_MOVTEXT_DECODER 0 +#define CONFIG_MPL2_DECODER 0 +#define CONFIG_PGSSUB_DECODER 0 +#define CONFIG_PJS_DECODER 0 +#define CONFIG_REALTEXT_DECODER 0 +#define CONFIG_SAMI_DECODER 0 +#define CONFIG_SRT_DECODER 0 +#define CONFIG_STL_DECODER 0 +#define CONFIG_SUBRIP_DECODER 0 +#define CONFIG_SUBVIEWER_DECODER 0 +#define CONFIG_SUBVIEWER1_DECODER 0 +#define CONFIG_TEXT_DECODER 0 +#define CONFIG_VPLAYER_DECODER 0 +#define CONFIG_WEBVTT_DECODER 0 +#define CONFIG_XSUB_DECODER 0 +#define CONFIG_LIBCELT_DECODER 0 +#define CONFIG_LIBFDK_AAC_DECODER 0 +#define CONFIG_LIBGSM_DECODER 0 +#define CONFIG_LIBGSM_MS_DECODER 0 +#define CONFIG_LIBILBC_DECODER 0 +#define CONFIG_LIBOPENCORE_AMRNB_DECODER 0 +#define CONFIG_LIBOPENCORE_AMRWB_DECODER 0 +#define CONFIG_LIBOPENJPEG_DECODER 0 +#define CONFIG_LIBOPUS_DECODER 0 +#define CONFIG_LIBSCHROEDINGER_DECODER 0 +#define CONFIG_LIBSPEEX_DECODER 0 +#define CONFIG_LIBSTAGEFRIGHT_H264_DECODER 0 +#define CONFIG_LIBUTVIDEO_DECODER 0 +#define CONFIG_LIBVORBIS_DECODER 0 +#define CONFIG_LIBVPX_VP8_DECODER 0 +#define CONFIG_LIBVPX_VP9_DECODER 0 +#define CONFIG_LIBZVBI_TELETEXT_DECODER 0 +#define CONFIG_BINTEXT_DECODER 0 +#define CONFIG_XBIN_DECODER 0 +#define CONFIG_IDF_DECODER 0 +#define CONFIG_AAC_DEMUXER 0 +#define CONFIG_AC3_DEMUXER 0 +#define CONFIG_ACT_DEMUXER 0 +#define CONFIG_ADF_DEMUXER 0 +#define CONFIG_ADP_DEMUXER 0 +#define CONFIG_ADX_DEMUXER 0 +#define CONFIG_AEA_DEMUXER 0 +#define CONFIG_AFC_DEMUXER 0 +#define CONFIG_AIFF_DEMUXER 0 +#define CONFIG_AMR_DEMUXER 0 +#define CONFIG_ANM_DEMUXER 0 +#define CONFIG_APC_DEMUXER 0 +#define CONFIG_APE_DEMUXER 0 +#define CONFIG_AQTITLE_DEMUXER 0 +#define CONFIG_ASF_DEMUXER 0 +#define CONFIG_ASS_DEMUXER 0 +#define CONFIG_AST_DEMUXER 0 +#define CONFIG_AU_DEMUXER 0 +#define CONFIG_AVI_DEMUXER 0 +#define CONFIG_AVISYNTH_DEMUXER 0 +#define CONFIG_AVR_DEMUXER 0 +#define CONFIG_AVS_DEMUXER 0 +#define CONFIG_BETHSOFTVID_DEMUXER 0 +#define CONFIG_BFI_DEMUXER 0 +#define CONFIG_BINTEXT_DEMUXER 0 +#define CONFIG_BINK_DEMUXER 0 +#define CONFIG_BIT_DEMUXER 0 +#define CONFIG_BMV_DEMUXER 0 +#define CONFIG_BRSTM_DEMUXER 0 +#define CONFIG_BOA_DEMUXER 0 +#define CONFIG_C93_DEMUXER 0 +#define CONFIG_CAF_DEMUXER 0 +#define CONFIG_CAVSVIDEO_DEMUXER 0 +#define CONFIG_CDG_DEMUXER 0 +#define CONFIG_CDXL_DEMUXER 0 +#define CONFIG_CINE_DEMUXER 0 +#define CONFIG_CONCAT_DEMUXER 0 +#define CONFIG_DATA_DEMUXER 0 +#define CONFIG_DAUD_DEMUXER 0 +#define CONFIG_DFA_DEMUXER 0 +#define CONFIG_DIRAC_DEMUXER 0 +#define CONFIG_DNXHD_DEMUXER 0 +#define CONFIG_DSF_DEMUXER 0 +#define CONFIG_DSICIN_DEMUXER 0 +#define CONFIG_DTS_DEMUXER 0 +#define CONFIG_DTSHD_DEMUXER 0 +#define CONFIG_DV_DEMUXER 0 +#define CONFIG_DXA_DEMUXER 0 +#define CONFIG_EA_DEMUXER 0 +#define CONFIG_EA_CDATA_DEMUXER 0 +#define CONFIG_EAC3_DEMUXER 0 +#define CONFIG_EPAF_DEMUXER 0 +#define CONFIG_FFM_DEMUXER 0 +#define CONFIG_FFMETADATA_DEMUXER 0 +#define CONFIG_FILMSTRIP_DEMUXER 0 +#define CONFIG_FLAC_DEMUXER 0 +#define CONFIG_FLIC_DEMUXER 0 +#define CONFIG_FLV_DEMUXER 0 +#define CONFIG_LIVE_FLV_DEMUXER 0 +#define CONFIG_FOURXM_DEMUXER 0 +#define CONFIG_FRM_DEMUXER 0 +#define CONFIG_G722_DEMUXER 0 +#define CONFIG_G723_1_DEMUXER 0 +#define CONFIG_G729_DEMUXER 0 +#define CONFIG_GIF_DEMUXER 0 +#define CONFIG_GSM_DEMUXER 0 +#define CONFIG_GXF_DEMUXER 0 +#define CONFIG_H261_DEMUXER 0 +#define CONFIG_H263_DEMUXER 0 +#define CONFIG_H264_DEMUXER 0 +#define CONFIG_HEVC_DEMUXER 1 +#define CONFIG_HLS_DEMUXER 0 +#define CONFIG_HNM_DEMUXER 0 +#define CONFIG_ICO_DEMUXER 0 +#define CONFIG_IDCIN_DEMUXER 0 +#define CONFIG_IDF_DEMUXER 0 +#define CONFIG_IFF_DEMUXER 0 +#define CONFIG_ILBC_DEMUXER 0 +#define CONFIG_IMAGE2_DEMUXER 0 +#define CONFIG_IMAGE2PIPE_DEMUXER 0 +#define CONFIG_IMAGE2_ALIAS_PIX_DEMUXER 0 +#define CONFIG_IMAGE2_BRENDER_PIX_DEMUXER 0 +#define CONFIG_INGENIENT_DEMUXER 0 +#define CONFIG_IPMOVIE_DEMUXER 0 +#define CONFIG_IRCAM_DEMUXER 0 +#define CONFIG_ISS_DEMUXER 0 +#define CONFIG_IV8_DEMUXER 0 +#define CONFIG_IVF_DEMUXER 0 +#define CONFIG_JACOSUB_DEMUXER 0 +#define CONFIG_JV_DEMUXER 0 +#define CONFIG_LATM_DEMUXER 0 +#define CONFIG_LMLM4_DEMUXER 0 +#define CONFIG_LOAS_DEMUXER 0 +#define CONFIG_LRC_DEMUXER 0 +#define CONFIG_LVF_DEMUXER 0 +#define CONFIG_LXF_DEMUXER 0 +#define CONFIG_M4V_DEMUXER 0 +#define CONFIG_MATROSKA_DEMUXER 0 +#define CONFIG_MGSTS_DEMUXER 0 +#define CONFIG_MICRODVD_DEMUXER 0 +#define CONFIG_MJPEG_DEMUXER 0 +#define CONFIG_MLP_DEMUXER 0 +#define CONFIG_MLV_DEMUXER 0 +#define CONFIG_MM_DEMUXER 0 +#define CONFIG_MMF_DEMUXER 0 +#define CONFIG_MOV_DEMUXER 0 +#define CONFIG_MP3_DEMUXER 0 +#define CONFIG_MPC_DEMUXER 0 +#define CONFIG_MPC8_DEMUXER 0 +#define CONFIG_MPEGPS_DEMUXER 0 +#define CONFIG_MPEGTS_DEMUXER 0 +#define CONFIG_MPEGTSRAW_DEMUXER 0 +#define CONFIG_MPEGVIDEO_DEMUXER 0 +#define CONFIG_MPL2_DEMUXER 0 +#define CONFIG_MPSUB_DEMUXER 0 +#define CONFIG_MSNWC_TCP_DEMUXER 0 +#define CONFIG_MTV_DEMUXER 0 +#define CONFIG_MV_DEMUXER 0 +#define CONFIG_MVI_DEMUXER 0 +#define CONFIG_MXF_DEMUXER 0 +#define CONFIG_MXG_DEMUXER 0 +#define CONFIG_NC_DEMUXER 0 +#define CONFIG_NISTSPHERE_DEMUXER 0 +#define CONFIG_NSV_DEMUXER 0 +#define CONFIG_NUT_DEMUXER 0 +#define CONFIG_NUV_DEMUXER 0 +#define CONFIG_OGG_DEMUXER 0 +#define CONFIG_OMA_DEMUXER 0 +#define CONFIG_PAF_DEMUXER 0 +#define CONFIG_PCM_ALAW_DEMUXER 0 +#define CONFIG_PCM_MULAW_DEMUXER 0 +#define CONFIG_PCM_F64BE_DEMUXER 0 +#define CONFIG_PCM_F64LE_DEMUXER 0 +#define CONFIG_PCM_F32BE_DEMUXER 0 +#define CONFIG_PCM_F32LE_DEMUXER 0 +#define CONFIG_PCM_S32BE_DEMUXER 0 +#define CONFIG_PCM_S32LE_DEMUXER 0 +#define CONFIG_PCM_S24BE_DEMUXER 0 +#define CONFIG_PCM_S24LE_DEMUXER 0 +#define CONFIG_PCM_S16BE_DEMUXER 0 +#define CONFIG_PCM_S16LE_DEMUXER 0 +#define CONFIG_PCM_S8_DEMUXER 0 +#define CONFIG_PCM_U32BE_DEMUXER 0 +#define CONFIG_PCM_U32LE_DEMUXER 0 +#define CONFIG_PCM_U24BE_DEMUXER 0 +#define CONFIG_PCM_U24LE_DEMUXER 0 +#define CONFIG_PCM_U16BE_DEMUXER 0 +#define CONFIG_PCM_U16LE_DEMUXER 0 +#define CONFIG_PCM_U8_DEMUXER 0 +#define CONFIG_PJS_DEMUXER 0 +#define CONFIG_PMP_DEMUXER 0 +#define CONFIG_PVA_DEMUXER 0 +#define CONFIG_PVF_DEMUXER 0 +#define CONFIG_QCP_DEMUXER 0 +#define CONFIG_R3D_DEMUXER 0 +#define CONFIG_RAWVIDEO_DEMUXER 0 +#define CONFIG_REALTEXT_DEMUXER 0 +#define CONFIG_REDSPARK_DEMUXER 0 +#define CONFIG_RL2_DEMUXER 0 +#define CONFIG_RM_DEMUXER 0 +#define CONFIG_ROQ_DEMUXER 0 +#define CONFIG_RPL_DEMUXER 0 +#define CONFIG_RSD_DEMUXER 0 +#define CONFIG_RSO_DEMUXER 0 +#define CONFIG_RTP_DEMUXER 0 +#define CONFIG_RTSP_DEMUXER 0 +#define CONFIG_SAMI_DEMUXER 0 +#define CONFIG_SAP_DEMUXER 0 +#define CONFIG_SBG_DEMUXER 0 +#define CONFIG_SDP_DEMUXER 0 +#define CONFIG_SDR2_DEMUXER 0 +#define CONFIG_SEGAFILM_DEMUXER 0 +#define CONFIG_SHORTEN_DEMUXER 0 +#define CONFIG_SIFF_DEMUXER 0 +#define CONFIG_SLN_DEMUXER 0 +#define CONFIG_SMACKER_DEMUXER 0 +#define CONFIG_SMJPEG_DEMUXER 0 +#define CONFIG_SMUSH_DEMUXER 0 +#define CONFIG_SOL_DEMUXER 0 +#define CONFIG_SOX_DEMUXER 0 +#define CONFIG_SPDIF_DEMUXER 0 +#define CONFIG_SRT_DEMUXER 0 +#define CONFIG_STR_DEMUXER 0 +#define CONFIG_STL_DEMUXER 0 +#define CONFIG_SUBVIEWER1_DEMUXER 0 +#define CONFIG_SUBVIEWER_DEMUXER 0 +#define CONFIG_SUP_DEMUXER 0 +#define CONFIG_SWF_DEMUXER 0 +#define CONFIG_TAK_DEMUXER 0 +#define CONFIG_TEDCAPTIONS_DEMUXER 0 +#define CONFIG_THP_DEMUXER 0 +#define CONFIG_TIERTEXSEQ_DEMUXER 0 +#define CONFIG_TMV_DEMUXER 0 +#define CONFIG_TRUEHD_DEMUXER 0 +#define CONFIG_TTA_DEMUXER 0 +#define CONFIG_TXD_DEMUXER 0 +#define CONFIG_TTY_DEMUXER 0 +#define CONFIG_VC1_DEMUXER 0 +#define CONFIG_VC1T_DEMUXER 0 +#define CONFIG_VIVO_DEMUXER 0 +#define CONFIG_VMD_DEMUXER 0 +#define CONFIG_VOBSUB_DEMUXER 0 +#define CONFIG_VOC_DEMUXER 0 +#define CONFIG_VPLAYER_DEMUXER 0 +#define CONFIG_VQF_DEMUXER 0 +#define CONFIG_W64_DEMUXER 0 +#define CONFIG_WAV_DEMUXER 0 +#define CONFIG_WC3_DEMUXER 0 +#define CONFIG_WEBM_DASH_MANIFEST_DEMUXER 0 +#define CONFIG_WEBVTT_DEMUXER 0 +#define CONFIG_WSAUD_DEMUXER 0 +#define CONFIG_WSVQA_DEMUXER 0 +#define CONFIG_WTV_DEMUXER 0 +#define CONFIG_WV_DEMUXER 0 +#define CONFIG_XA_DEMUXER 0 +#define CONFIG_XBIN_DEMUXER 0 +#define CONFIG_XMV_DEMUXER 0 +#define CONFIG_XWMA_DEMUXER 0 +#define CONFIG_YOP_DEMUXER 0 +#define CONFIG_YUV4MPEGPIPE_DEMUXER 0 +#define CONFIG_IMAGE_BMP_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_DPX_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_EXR_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_J2K_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEG_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PICTOR_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PNG_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_SGI_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_TIFF_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_WEBP_PIPE_DEMUXER 0 +#define CONFIG_LIBGME_DEMUXER 0 +#define CONFIG_LIBMODPLUG_DEMUXER 0 +#define CONFIG_LIBNUT_DEMUXER 0 +#define CONFIG_LIBQUVI_DEMUXER 0 +#define CONFIG_A64MULTI_ENCODER 0 +#define CONFIG_A64MULTI5_ENCODER 0 +#define CONFIG_ALIAS_PIX_ENCODER 0 +#define CONFIG_AMV_ENCODER 0 +#define CONFIG_ASV1_ENCODER 0 +#define CONFIG_ASV2_ENCODER 0 +#define CONFIG_AVRP_ENCODER 0 +#define CONFIG_AVUI_ENCODER 0 +#define CONFIG_AYUV_ENCODER 0 +#define CONFIG_BMP_ENCODER 0 +#define CONFIG_CINEPAK_ENCODER 0 +#define CONFIG_CLJR_ENCODER 0 +#define CONFIG_COMFORTNOISE_ENCODER 0 +#define CONFIG_DNXHD_ENCODER 0 +#define CONFIG_DPX_ENCODER 0 +#define CONFIG_DVVIDEO_ENCODER 0 +#define CONFIG_FFV1_ENCODER 0 +#define CONFIG_FFVHUFF_ENCODER 0 +#define CONFIG_FLASHSV_ENCODER 0 +#define CONFIG_FLASHSV2_ENCODER 0 +#define CONFIG_FLV_ENCODER 0 +#define CONFIG_GIF_ENCODER 0 +#define CONFIG_H261_ENCODER 0 +#define CONFIG_H263_ENCODER 0 +#define CONFIG_H263P_ENCODER 0 +#define CONFIG_HUFFYUV_ENCODER 0 +#define CONFIG_JPEG2000_ENCODER 0 +#define CONFIG_JPEGLS_ENCODER 0 +#define CONFIG_LJPEG_ENCODER 0 +#define CONFIG_MJPEG_ENCODER 0 +#define CONFIG_MPEG1VIDEO_ENCODER 0 +#define CONFIG_MPEG2VIDEO_ENCODER 0 +#define CONFIG_MPEG4_ENCODER 0 +#define CONFIG_MSMPEG4V2_ENCODER 0 +#define CONFIG_MSMPEG4V3_ENCODER 0 +#define CONFIG_MSVIDEO1_ENCODER 0 +#define CONFIG_PAM_ENCODER 0 +#define CONFIG_PBM_ENCODER 0 +#define CONFIG_PCX_ENCODER 0 +#define CONFIG_PGM_ENCODER 0 +#define CONFIG_PGMYUV_ENCODER 0 +#define CONFIG_PNG_ENCODER 0 +#define CONFIG_PPM_ENCODER 0 +#define CONFIG_PRORES_ENCODER 0 +#define CONFIG_PRORES_AW_ENCODER 0 +#define CONFIG_PRORES_KS_ENCODER 0 +#define CONFIG_QTRLE_ENCODER 0 +#define CONFIG_R10K_ENCODER 0 +#define CONFIG_R210_ENCODER 0 +#define CONFIG_RAWVIDEO_ENCODER 0 +#define CONFIG_ROQ_ENCODER 0 +#define CONFIG_RV10_ENCODER 0 +#define CONFIG_RV20_ENCODER 0 +#define CONFIG_S302M_ENCODER 0 +#define CONFIG_SGI_ENCODER 0 +#define CONFIG_SNOW_ENCODER 0 +#define CONFIG_SUNRAST_ENCODER 0 +#define CONFIG_SVQ1_ENCODER 0 +#define CONFIG_TARGA_ENCODER 0 +#define CONFIG_TIFF_ENCODER 0 +#define CONFIG_UTVIDEO_ENCODER 0 +#define CONFIG_V210_ENCODER 0 +#define CONFIG_V308_ENCODER 0 +#define CONFIG_V408_ENCODER 0 +#define CONFIG_V410_ENCODER 0 +#define CONFIG_WMV1_ENCODER 0 +#define CONFIG_WMV2_ENCODER 0 +#define CONFIG_XBM_ENCODER 0 +#define CONFIG_XFACE_ENCODER 0 +#define CONFIG_XWD_ENCODER 0 +#define CONFIG_Y41P_ENCODER 0 +#define CONFIG_YUV4_ENCODER 0 +#define CONFIG_ZLIB_ENCODER 0 +#define CONFIG_ZMBV_ENCODER 0 +#define CONFIG_AAC_ENCODER 0 +#define CONFIG_AC3_ENCODER 0 +#define CONFIG_AC3_FIXED_ENCODER 0 +#define CONFIG_ALAC_ENCODER 0 +#define CONFIG_DCA_ENCODER 0 +#define CONFIG_EAC3_ENCODER 0 +#define CONFIG_FLAC_ENCODER 0 +#define CONFIG_G723_1_ENCODER 0 +#define CONFIG_MP2_ENCODER 0 +#define CONFIG_MP2FIXED_ENCODER 0 +#define CONFIG_NELLYMOSER_ENCODER 0 +#define CONFIG_RA_144_ENCODER 0 +#define CONFIG_SONIC_ENCODER 0 +#define CONFIG_SONIC_LS_ENCODER 0 +#define CONFIG_TTA_ENCODER 0 +#define CONFIG_VORBIS_ENCODER 0 +#define CONFIG_WAVPACK_ENCODER 0 +#define CONFIG_WMAV1_ENCODER 0 +#define CONFIG_WMAV2_ENCODER 0 +#define CONFIG_PCM_ALAW_ENCODER 0 +#define CONFIG_PCM_F32BE_ENCODER 0 +#define CONFIG_PCM_F32LE_ENCODER 0 +#define CONFIG_PCM_F64BE_ENCODER 0 +#define CONFIG_PCM_F64LE_ENCODER 0 +#define CONFIG_PCM_MULAW_ENCODER 0 +#define CONFIG_PCM_S8_ENCODER 0 +#define CONFIG_PCM_S8_PLANAR_ENCODER 0 +#define CONFIG_PCM_S16BE_ENCODER 0 +#define CONFIG_PCM_S16BE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S16LE_ENCODER 0 +#define CONFIG_PCM_S16LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S24BE_ENCODER 0 +#define CONFIG_PCM_S24DAUD_ENCODER 0 +#define CONFIG_PCM_S24LE_ENCODER 0 +#define CONFIG_PCM_S24LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S32BE_ENCODER 0 +#define CONFIG_PCM_S32LE_ENCODER 0 +#define CONFIG_PCM_S32LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_U8_ENCODER 0 +#define CONFIG_PCM_U16BE_ENCODER 0 +#define CONFIG_PCM_U16LE_ENCODER 0 +#define CONFIG_PCM_U24BE_ENCODER 0 +#define CONFIG_PCM_U24LE_ENCODER 0 +#define CONFIG_PCM_U32BE_ENCODER 0 +#define CONFIG_PCM_U32LE_ENCODER 0 +#define CONFIG_ROQ_DPCM_ENCODER 0 +#define CONFIG_ADPCM_ADX_ENCODER 0 +#define CONFIG_ADPCM_G722_ENCODER 0 +#define CONFIG_ADPCM_G726_ENCODER 0 +#define CONFIG_ADPCM_IMA_QT_ENCODER 0 +#define CONFIG_ADPCM_IMA_WAV_ENCODER 0 +#define CONFIG_ADPCM_MS_ENCODER 0 +#define CONFIG_ADPCM_SWF_ENCODER 0 +#define CONFIG_ADPCM_YAMAHA_ENCODER 0 +#define CONFIG_SSA_ENCODER 0 +#define CONFIG_ASS_ENCODER 0 +#define CONFIG_DVBSUB_ENCODER 0 +#define CONFIG_DVDSUB_ENCODER 0 +#define CONFIG_MOVTEXT_ENCODER 0 +#define CONFIG_SRT_ENCODER 0 +#define CONFIG_SUBRIP_ENCODER 0 +#define CONFIG_WEBVTT_ENCODER 0 +#define CONFIG_XSUB_ENCODER 0 +#define CONFIG_LIBFAAC_ENCODER 0 +#define CONFIG_LIBFDK_AAC_ENCODER 0 +#define CONFIG_LIBGSM_ENCODER 0 +#define CONFIG_LIBGSM_MS_ENCODER 0 +#define CONFIG_LIBILBC_ENCODER 0 +#define CONFIG_LIBMP3LAME_ENCODER 0 +#define CONFIG_LIBOPENCORE_AMRNB_ENCODER 0 +#define CONFIG_LIBOPENJPEG_ENCODER 0 +#define CONFIG_LIBOPUS_ENCODER 0 +#define CONFIG_LIBSCHROEDINGER_ENCODER 0 +#define CONFIG_LIBSHINE_ENCODER 0 +#define CONFIG_LIBSPEEX_ENCODER 0 +#define CONFIG_LIBTHEORA_ENCODER 0 +#define CONFIG_LIBTWOLAME_ENCODER 0 +#define CONFIG_LIBUTVIDEO_ENCODER 0 +#define CONFIG_LIBVO_AACENC_ENCODER 0 +#define CONFIG_LIBVO_AMRWBENC_ENCODER 0 +#define CONFIG_LIBVORBIS_ENCODER 0 +#define CONFIG_LIBVPX_VP8_ENCODER 0 +#define CONFIG_LIBVPX_VP9_ENCODER 0 +#define CONFIG_LIBWAVPACK_ENCODER 0 +#define CONFIG_LIBWEBP_ENCODER 0 +#define CONFIG_LIBX264_ENCODER 0 +#define CONFIG_LIBX264RGB_ENCODER 0 +#define CONFIG_LIBX265_ENCODER 0 +#define CONFIG_LIBXAVS_ENCODER 0 +#define CONFIG_LIBXVID_ENCODER 0 +#define CONFIG_LIBAACPLUS_ENCODER 0 +#define CONFIG_ADELAY_FILTER 0 +#define CONFIG_AECHO_FILTER 0 +#define CONFIG_AEVAL_FILTER 0 +#define CONFIG_AFADE_FILTER 0 +#define CONFIG_AFORMAT_FILTER 1 +#define CONFIG_AINTERLEAVE_FILTER 0 +#define CONFIG_ALLPASS_FILTER 0 +#define CONFIG_AMERGE_FILTER 0 +#define CONFIG_AMIX_FILTER 0 +#define CONFIG_ANULL_FILTER 1 +#define CONFIG_APAD_FILTER 0 +#define CONFIG_APERMS_FILTER 0 +#define CONFIG_APHASER_FILTER 0 +#define CONFIG_ARESAMPLE_FILTER 0 +#define CONFIG_ASELECT_FILTER 0 +#define CONFIG_ASENDCMD_FILTER 0 +#define CONFIG_ASETNSAMPLES_FILTER 0 +#define CONFIG_ASETPTS_FILTER 0 +#define CONFIG_ASETRATE_FILTER 0 +#define CONFIG_ASETTB_FILTER 0 +#define CONFIG_ASHOWINFO_FILTER 0 +#define CONFIG_ASPLIT_FILTER 0 +#define CONFIG_ASTATS_FILTER 0 +#define CONFIG_ASTREAMSYNC_FILTER 0 +#define CONFIG_ASYNCTS_FILTER 0 +#define CONFIG_ATEMPO_FILTER 0 +#define CONFIG_ATRIM_FILTER 1 +#define CONFIG_AZMQ_FILTER 0 +#define CONFIG_BANDPASS_FILTER 0 +#define CONFIG_BANDREJECT_FILTER 0 +#define CONFIG_BASS_FILTER 0 +#define CONFIG_BIQUAD_FILTER 0 +#define CONFIG_BS2B_FILTER 0 +#define CONFIG_CHANNELMAP_FILTER 0 +#define CONFIG_CHANNELSPLIT_FILTER 0 +#define CONFIG_COMPAND_FILTER 0 +#define CONFIG_EARWAX_FILTER 0 +#define CONFIG_EBUR128_FILTER 0 +#define CONFIG_EQUALIZER_FILTER 0 +#define CONFIG_FLANGER_FILTER 0 +#define CONFIG_HIGHPASS_FILTER 0 +#define CONFIG_JOIN_FILTER 0 +#define CONFIG_LADSPA_FILTER 0 +#define CONFIG_LOWPASS_FILTER 0 +#define CONFIG_PAN_FILTER 0 +#define CONFIG_REPLAYGAIN_FILTER 0 +#define CONFIG_RESAMPLE_FILTER 0 +#define CONFIG_SILENCEDETECT_FILTER 0 +#define CONFIG_SILENCEREMOVE_FILTER 0 +#define CONFIG_TREBLE_FILTER 0 +#define CONFIG_VOLUME_FILTER 0 +#define CONFIG_VOLUMEDETECT_FILTER 0 +#define CONFIG_AEVALSRC_FILTER 0 +#define CONFIG_ANULLSRC_FILTER 0 +#define CONFIG_FLITE_FILTER 0 +#define CONFIG_SINE_FILTER 0 +#define CONFIG_ANULLSINK_FILTER 0 +#define CONFIG_ALPHAEXTRACT_FILTER 0 +#define CONFIG_ALPHAMERGE_FILTER 0 +#define CONFIG_ASS_FILTER 0 +#define CONFIG_BBOX_FILTER 0 +#define CONFIG_BLACKDETECT_FILTER 0 +#define CONFIG_BLACKFRAME_FILTER 0 +#define CONFIG_BLEND_FILTER 0 +#define CONFIG_BOXBLUR_FILTER 0 +#define CONFIG_CODECVIEW_FILTER 0 +#define CONFIG_COLORBALANCE_FILTER 0 +#define CONFIG_COLORCHANNELMIXER_FILTER 0 +#define CONFIG_COLORMATRIX_FILTER 0 +#define CONFIG_COPY_FILTER 0 +#define CONFIG_CROP_FILTER 1 +#define CONFIG_CROPDETECT_FILTER 0 +#define CONFIG_CURVES_FILTER 0 +#define CONFIG_DCTDNOIZ_FILTER 0 +#define CONFIG_DECIMATE_FILTER 0 +#define CONFIG_DEJUDDER_FILTER 0 +#define CONFIG_DELOGO_FILTER 0 +#define CONFIG_DESHAKE_FILTER 0 +#define CONFIG_DRAWBOX_FILTER 0 +#define CONFIG_DRAWGRID_FILTER 0 +#define CONFIG_DRAWTEXT_FILTER 0 +#define CONFIG_EDGEDETECT_FILTER 0 +#define CONFIG_ELBG_FILTER 0 +#define CONFIG_EXTRACTPLANES_FILTER 0 +#define CONFIG_FADE_FILTER 0 +#define CONFIG_FIELD_FILTER 0 +#define CONFIG_FIELDMATCH_FILTER 0 +#define CONFIG_FIELDORDER_FILTER 0 +#define CONFIG_FORMAT_FILTER 1 +#define CONFIG_FPS_FILTER 0 +#define CONFIG_FRAMEPACK_FILTER 0 +#define CONFIG_FRAMESTEP_FILTER 0 +#define CONFIG_FREI0R_FILTER 0 +#define CONFIG_GEQ_FILTER 0 +#define CONFIG_GRADFUN_FILTER 0 +#define CONFIG_HALDCLUT_FILTER 0 +#define CONFIG_HFLIP_FILTER 1 +#define CONFIG_HISTEQ_FILTER 0 +#define CONFIG_HISTOGRAM_FILTER 0 +#define CONFIG_HQDN3D_FILTER 0 +#define CONFIG_HQX_FILTER 0 +#define CONFIG_HUE_FILTER 0 +#define CONFIG_IDET_FILTER 0 +#define CONFIG_IL_FILTER 0 +#define CONFIG_INTERLACE_FILTER 0 +#define CONFIG_INTERLEAVE_FILTER 0 +#define CONFIG_KERNDEINT_FILTER 0 +#define CONFIG_LENSCORRECTION_FILTER 0 +#define CONFIG_LUT3D_FILTER 0 +#define CONFIG_LUT_FILTER 0 +#define CONFIG_LUTRGB_FILTER 0 +#define CONFIG_LUTYUV_FILTER 0 +#define CONFIG_MCDEINT_FILTER 0 +#define CONFIG_MERGEPLANES_FILTER 0 +#define CONFIG_MP_FILTER 0 +#define CONFIG_MPDECIMATE_FILTER 0 +#define CONFIG_NEGATE_FILTER 0 +#define CONFIG_NOFORMAT_FILTER 0 +#define CONFIG_NOISE_FILTER 0 +#define CONFIG_NULL_FILTER 1 +#define CONFIG_OCV_FILTER 0 +#define CONFIG_OVERLAY_FILTER 0 +#define CONFIG_OWDENOISE_FILTER 0 +#define CONFIG_PAD_FILTER 0 +#define CONFIG_PERMS_FILTER 0 +#define CONFIG_PERSPECTIVE_FILTER 0 +#define CONFIG_PHASE_FILTER 0 +#define CONFIG_PIXDESCTEST_FILTER 0 +#define CONFIG_PP_FILTER 0 +#define CONFIG_PSNR_FILTER 0 +#define CONFIG_PULLUP_FILTER 0 +#define CONFIG_REMOVELOGO_FILTER 0 +#define CONFIG_ROTATE_FILTER 1 +#define CONFIG_SAB_FILTER 0 +#define CONFIG_SCALE_FILTER 0 +#define CONFIG_SELECT_FILTER 0 +#define CONFIG_SENDCMD_FILTER 0 +#define CONFIG_SEPARATEFIELDS_FILTER 0 +#define CONFIG_SETDAR_FILTER 0 +#define CONFIG_SETFIELD_FILTER 0 +#define CONFIG_SETPTS_FILTER 1 +#define CONFIG_SETSAR_FILTER 0 +#define CONFIG_SETTB_FILTER 0 +#define CONFIG_SHOWINFO_FILTER 0 +#define CONFIG_SHUFFLEPLANES_FILTER 0 +#define CONFIG_SIGNALSTATS_FILTER 0 +#define CONFIG_SMARTBLUR_FILTER 0 +#define CONFIG_SPLIT_FILTER 0 +#define CONFIG_SPP_FILTER 0 +#define CONFIG_STEREO3D_FILTER 0 +#define CONFIG_SUBTITLES_FILTER 0 +#define CONFIG_SUPER2XSAI_FILTER 0 +#define CONFIG_SWAPUV_FILTER 0 +#define CONFIG_TELECINE_FILTER 0 +#define CONFIG_THUMBNAIL_FILTER 0 +#define CONFIG_TILE_FILTER 0 +#define CONFIG_TINTERLACE_FILTER 0 +#define CONFIG_TRANSPOSE_FILTER 1 +#define CONFIG_TRIM_FILTER 1 +#define CONFIG_UNSHARP_FILTER 0 +#define CONFIG_VFLIP_FILTER 1 +#define CONFIG_VIDSTABDETECT_FILTER 0 +#define CONFIG_VIDSTABTRANSFORM_FILTER 0 +#define CONFIG_VIGNETTE_FILTER 0 +#define CONFIG_W3FDIF_FILTER 0 +#define CONFIG_XBR_FILTER 0 +#define CONFIG_YADIF_FILTER 0 +#define CONFIG_ZMQ_FILTER 0 +#define CONFIG_ZOOMPAN_FILTER 0 +#define CONFIG_CELLAUTO_FILTER 0 +#define CONFIG_COLOR_FILTER 0 +#define CONFIG_FREI0R_SRC_FILTER 0 +#define CONFIG_HALDCLUTSRC_FILTER 0 +#define CONFIG_LIFE_FILTER 0 +#define CONFIG_MANDELBROT_FILTER 0 +#define CONFIG_MPTESTSRC_FILTER 0 +#define CONFIG_NULLSRC_FILTER 0 +#define CONFIG_RGBTESTSRC_FILTER 0 +#define CONFIG_SMPTEBARS_FILTER 0 +#define CONFIG_SMPTEHDBARS_FILTER 0 +#define CONFIG_TESTSRC_FILTER 0 +#define CONFIG_NULLSINK_FILTER 0 +#define CONFIG_AVECTORSCOPE_FILTER 0 +#define CONFIG_CONCAT_FILTER 0 +#define CONFIG_SHOWCQT_FILTER 0 +#define CONFIG_SHOWSPECTRUM_FILTER 0 +#define CONFIG_SHOWWAVES_FILTER 0 +#define CONFIG_AMOVIE_FILTER 0 +#define CONFIG_MOVIE_FILTER 0 +#define CONFIG_H263_VAAPI_HWACCEL 0 +#define CONFIG_H263_VDPAU_HWACCEL 0 +#define CONFIG_H264_DXVA2_HWACCEL 0 +#define CONFIG_H264_VAAPI_HWACCEL 0 +#define CONFIG_H264_VDA_HWACCEL 0 +#define CONFIG_H264_VDA_OLD_HWACCEL 0 +#define CONFIG_H264_VDPAU_HWACCEL 0 +#define CONFIG_MPEG1_XVMC_HWACCEL 0 +#define CONFIG_MPEG1_VDPAU_HWACCEL 0 +#define CONFIG_MPEG2_XVMC_HWACCEL 0 +#define CONFIG_MPEG2_DXVA2_HWACCEL 0 +#define CONFIG_MPEG2_VAAPI_HWACCEL 0 +#define CONFIG_MPEG2_VDPAU_HWACCEL 0 +#define CONFIG_MPEG4_VAAPI_HWACCEL 0 +#define CONFIG_MPEG4_VDPAU_HWACCEL 0 +#define CONFIG_VC1_DXVA2_HWACCEL 0 +#define CONFIG_VC1_VAAPI_HWACCEL 0 +#define CONFIG_VC1_VDPAU_HWACCEL 0 +#define CONFIG_WMV3_DXVA2_HWACCEL 0 +#define CONFIG_WMV3_VAAPI_HWACCEL 0 +#define CONFIG_WMV3_VDPAU_HWACCEL 0 +#define CONFIG_ALSA_INDEV 0 +#define CONFIG_AVFOUNDATION_INDEV 0 +#define CONFIG_BKTR_INDEV 0 +#define CONFIG_DECKLINK_INDEV 0 +#define CONFIG_DSHOW_INDEV 0 +#define CONFIG_DV1394_INDEV 0 +#define CONFIG_FBDEV_INDEV 0 +#define CONFIG_GDIGRAB_INDEV 0 +#define CONFIG_IEC61883_INDEV 0 +#define CONFIG_JACK_INDEV 0 +#define CONFIG_LAVFI_INDEV 0 +#define CONFIG_OPENAL_INDEV 0 +#define CONFIG_OSS_INDEV 0 +#define CONFIG_PULSE_INDEV 0 +#define CONFIG_QTKIT_INDEV 0 +#define CONFIG_SNDIO_INDEV 0 +#define CONFIG_V4L2_INDEV 0 +#define CONFIG_VFWCAP_INDEV 0 +#define CONFIG_X11GRAB_INDEV 0 +#define CONFIG_X11GRAB_XCB_INDEV 0 +#define CONFIG_LIBCDIO_INDEV 0 +#define CONFIG_LIBDC1394_INDEV 0 +#define CONFIG_A64_MUXER 0 +#define CONFIG_AC3_MUXER 0 +#define CONFIG_ADTS_MUXER 0 +#define CONFIG_ADX_MUXER 0 +#define CONFIG_AIFF_MUXER 0 +#define CONFIG_AMR_MUXER 0 +#define CONFIG_ASF_MUXER 0 +#define CONFIG_ASS_MUXER 0 +#define CONFIG_AST_MUXER 0 +#define CONFIG_ASF_STREAM_MUXER 0 +#define CONFIG_AU_MUXER 0 +#define CONFIG_AVI_MUXER 0 +#define CONFIG_AVM2_MUXER 0 +#define CONFIG_BIT_MUXER 0 +#define CONFIG_CAF_MUXER 0 +#define CONFIG_CAVSVIDEO_MUXER 0 +#define CONFIG_CRC_MUXER 0 +#define CONFIG_DATA_MUXER 0 +#define CONFIG_DAUD_MUXER 0 +#define CONFIG_DIRAC_MUXER 0 +#define CONFIG_DNXHD_MUXER 0 +#define CONFIG_DTS_MUXER 0 +#define CONFIG_DV_MUXER 0 +#define CONFIG_EAC3_MUXER 0 +#define CONFIG_F4V_MUXER 0 +#define CONFIG_FFM_MUXER 0 +#define CONFIG_FFMETADATA_MUXER 0 +#define CONFIG_FILMSTRIP_MUXER 0 +#define CONFIG_FLAC_MUXER 0 +#define CONFIG_FLV_MUXER 0 +#define CONFIG_FRAMECRC_MUXER 0 +#define CONFIG_FRAMEMD5_MUXER 0 +#define CONFIG_G722_MUXER 0 +#define CONFIG_G723_1_MUXER 0 +#define CONFIG_GIF_MUXER 0 +#define CONFIG_GXF_MUXER 0 +#define CONFIG_H261_MUXER 0 +#define CONFIG_H263_MUXER 0 +#define CONFIG_H264_MUXER 0 +#define CONFIG_HDS_MUXER 0 +#define CONFIG_HEVC_MUXER 0 +#define CONFIG_HLS_MUXER 0 +#define CONFIG_ICO_MUXER 0 +#define CONFIG_ILBC_MUXER 0 +#define CONFIG_IMAGE2_MUXER 0 +#define CONFIG_IMAGE2PIPE_MUXER 0 +#define CONFIG_IPOD_MUXER 0 +#define CONFIG_IRCAM_MUXER 0 +#define CONFIG_ISMV_MUXER 0 +#define CONFIG_IVF_MUXER 0 +#define CONFIG_JACOSUB_MUXER 0 +#define CONFIG_LATM_MUXER 0 +#define CONFIG_LRC_MUXER 0 +#define CONFIG_M4V_MUXER 0 +#define CONFIG_MD5_MUXER 0 +#define CONFIG_MATROSKA_MUXER 0 +#define CONFIG_MATROSKA_AUDIO_MUXER 0 +#define CONFIG_MICRODVD_MUXER 0 +#define CONFIG_MJPEG_MUXER 0 +#define CONFIG_MLP_MUXER 0 +#define CONFIG_MMF_MUXER 0 +#define CONFIG_MOV_MUXER 0 +#define CONFIG_MP2_MUXER 0 +#define CONFIG_MP3_MUXER 0 +#define CONFIG_MP4_MUXER 0 +#define CONFIG_MPEG1SYSTEM_MUXER 0 +#define CONFIG_MPEG1VCD_MUXER 0 +#define CONFIG_MPEG1VIDEO_MUXER 0 +#define CONFIG_MPEG2DVD_MUXER 0 +#define CONFIG_MPEG2SVCD_MUXER 0 +#define CONFIG_MPEG2VIDEO_MUXER 0 +#define CONFIG_MPEG2VOB_MUXER 0 +#define CONFIG_MPEGTS_MUXER 0 +#define CONFIG_MPJPEG_MUXER 0 +#define CONFIG_MXF_MUXER 0 +#define CONFIG_MXF_D10_MUXER 0 +#define CONFIG_NULL_MUXER 0 +#define CONFIG_NUT_MUXER 0 +#define CONFIG_OGA_MUXER 0 +#define CONFIG_OGG_MUXER 0 +#define CONFIG_OMA_MUXER 0 +#define CONFIG_OPUS_MUXER 0 +#define CONFIG_PCM_ALAW_MUXER 0 +#define CONFIG_PCM_MULAW_MUXER 0 +#define CONFIG_PCM_F64BE_MUXER 0 +#define CONFIG_PCM_F64LE_MUXER 0 +#define CONFIG_PCM_F32BE_MUXER 0 +#define CONFIG_PCM_F32LE_MUXER 0 +#define CONFIG_PCM_S32BE_MUXER 0 +#define CONFIG_PCM_S32LE_MUXER 0 +#define CONFIG_PCM_S24BE_MUXER 0 +#define CONFIG_PCM_S24LE_MUXER 0 +#define CONFIG_PCM_S16BE_MUXER 0 +#define CONFIG_PCM_S16LE_MUXER 0 +#define CONFIG_PCM_S8_MUXER 0 +#define CONFIG_PCM_U32BE_MUXER 0 +#define CONFIG_PCM_U32LE_MUXER 0 +#define CONFIG_PCM_U24BE_MUXER 0 +#define CONFIG_PCM_U24LE_MUXER 0 +#define CONFIG_PCM_U16BE_MUXER 0 +#define CONFIG_PCM_U16LE_MUXER 0 +#define CONFIG_PCM_U8_MUXER 0 +#define CONFIG_PSP_MUXER 0 +#define CONFIG_RAWVIDEO_MUXER 0 +#define CONFIG_RM_MUXER 0 +#define CONFIG_ROQ_MUXER 0 +#define CONFIG_RSO_MUXER 0 +#define CONFIG_RTP_MUXER 0 +#define CONFIG_RTSP_MUXER 0 +#define CONFIG_SAP_MUXER 0 +#define CONFIG_SEGMENT_MUXER 0 +#define CONFIG_STREAM_SEGMENT_MUXER 0 +#define CONFIG_SMJPEG_MUXER 0 +#define CONFIG_SMOOTHSTREAMING_MUXER 0 +#define CONFIG_SOX_MUXER 0 +#define CONFIG_SPX_MUXER 0 +#define CONFIG_SPDIF_MUXER 0 +#define CONFIG_SRT_MUXER 0 +#define CONFIG_SWF_MUXER 0 +#define CONFIG_TEE_MUXER 0 +#define CONFIG_TG2_MUXER 0 +#define CONFIG_TGP_MUXER 0 +#define CONFIG_MKVTIMESTAMP_V2_MUXER 0 +#define CONFIG_TRUEHD_MUXER 0 +#define CONFIG_UNCODEDFRAMECRC_MUXER 0 +#define CONFIG_VC1_MUXER 0 +#define CONFIG_VC1T_MUXER 0 +#define CONFIG_VOC_MUXER 0 +#define CONFIG_W64_MUXER 0 +#define CONFIG_WAV_MUXER 0 +#define CONFIG_WEBM_MUXER 0 +#define CONFIG_WEBM_DASH_MANIFEST_MUXER 0 +#define CONFIG_WEBP_MUXER 0 +#define CONFIG_WEBVTT_MUXER 0 +#define CONFIG_WTV_MUXER 0 +#define CONFIG_WV_MUXER 0 +#define CONFIG_YUV4MPEGPIPE_MUXER 0 +#define CONFIG_LIBNUT_MUXER 0 +#define CONFIG_ALSA_OUTDEV 0 +#define CONFIG_CACA_OUTDEV 0 +#define CONFIG_DECKLINK_OUTDEV 0 +#define CONFIG_FBDEV_OUTDEV 0 +#define CONFIG_OPENGL_OUTDEV 0 +#define CONFIG_OSS_OUTDEV 0 +#define CONFIG_PULSE_OUTDEV 0 +#define CONFIG_SDL_OUTDEV 0 +#define CONFIG_SNDIO_OUTDEV 0 +#define CONFIG_V4L2_OUTDEV 0 +#define CONFIG_XV_OUTDEV 0 +#define CONFIG_AAC_PARSER 0 +#define CONFIG_AAC_LATM_PARSER 0 +#define CONFIG_AC3_PARSER 0 +#define CONFIG_ADX_PARSER 0 +#define CONFIG_BMP_PARSER 0 +#define CONFIG_CAVSVIDEO_PARSER 0 +#define CONFIG_COOK_PARSER 0 +#define CONFIG_DCA_PARSER 0 +#define CONFIG_DIRAC_PARSER 0 +#define CONFIG_DNXHD_PARSER 0 +#define CONFIG_DPX_PARSER 0 +#define CONFIG_DVBSUB_PARSER 0 +#define CONFIG_DVDSUB_PARSER 0 +#define CONFIG_DVD_NAV_PARSER 0 +#define CONFIG_FLAC_PARSER 0 +#define CONFIG_GSM_PARSER 0 +#define CONFIG_H261_PARSER 0 +#define CONFIG_H263_PARSER 0 +#define CONFIG_H264_PARSER 0 +#define CONFIG_HEVC_PARSER 0 +#define CONFIG_MJPEG_PARSER 0 +#define CONFIG_MLP_PARSER 0 +#define CONFIG_MPEG4VIDEO_PARSER 0 +#define CONFIG_MPEGAUDIO_PARSER 0 +#define CONFIG_MPEGVIDEO_PARSER 0 +#define CONFIG_OPUS_PARSER 0 +#define CONFIG_PNG_PARSER 0 +#define CONFIG_PNM_PARSER 0 +#define CONFIG_RV30_PARSER 0 +#define CONFIG_RV40_PARSER 0 +#define CONFIG_TAK_PARSER 0 +#define CONFIG_VC1_PARSER 0 +#define CONFIG_VORBIS_PARSER 0 +#define CONFIG_VP3_PARSER 0 +#define CONFIG_VP8_PARSER 0 +#define CONFIG_VP9_PARSER 0 +#define CONFIG_BLURAY_PROTOCOL 0 +#define CONFIG_CACHE_PROTOCOL 0 +#define CONFIG_CONCAT_PROTOCOL 0 +#define CONFIG_CRYPTO_PROTOCOL 0 +#define CONFIG_DATA_PROTOCOL 0 +#define CONFIG_FFRTMPCRYPT_PROTOCOL 0 +#define CONFIG_FFRTMPHTTP_PROTOCOL 0 +#define CONFIG_FILE_PROTOCOL 1 +#define CONFIG_FTP_PROTOCOL 0 +#define CONFIG_GOPHER_PROTOCOL 0 +#define CONFIG_HLS_PROTOCOL 0 +#define CONFIG_HTTP_PROTOCOL 0 +#define CONFIG_HTTPPROXY_PROTOCOL 0 +#define CONFIG_HTTPS_PROTOCOL 0 +#define CONFIG_ICECAST_PROTOCOL 0 +#define CONFIG_MMSH_PROTOCOL 0 +#define CONFIG_MMST_PROTOCOL 0 +#define CONFIG_MD5_PROTOCOL 0 +#define CONFIG_PIPE_PROTOCOL 0 +#define CONFIG_RTMP_PROTOCOL 0 +#define CONFIG_RTMPE_PROTOCOL 0 +#define CONFIG_RTMPS_PROTOCOL 0 +#define CONFIG_RTMPT_PROTOCOL 0 +#define CONFIG_RTMPTE_PROTOCOL 0 +#define CONFIG_RTMPTS_PROTOCOL 0 +#define CONFIG_RTP_PROTOCOL 0 +#define CONFIG_SCTP_PROTOCOL 0 +#define CONFIG_SRTP_PROTOCOL 0 +#define CONFIG_SUBFILE_PROTOCOL 0 +#define CONFIG_TCP_PROTOCOL 0 +#define CONFIG_TLS_PROTOCOL 0 +#define CONFIG_UDP_PROTOCOL 0 +#define CONFIG_UDPLITE_PROTOCOL 0 +#define CONFIG_UNIX_PROTOCOL 0 +#define CONFIG_LIBRTMP_PROTOCOL 0 +#define CONFIG_LIBRTMPE_PROTOCOL 0 +#define CONFIG_LIBRTMPS_PROTOCOL 0 +#define CONFIG_LIBRTMPT_PROTOCOL 0 +#define CONFIG_LIBRTMPTE_PROTOCOL 0 +#define CONFIG_LIBSSH_PROTOCOL 0 +#define CONFIG_LIBSMBCLIENT_PROTOCOL 0 + +/* HEVC decoder options */ +//#define USE_MD5 /* include MD5 SEI check */ +#define USE_MSPS /* support modified SPS header to simplify decoder */ +//#define USE_VAR_BIT_DEPTH /* support all bit depths with reduced code size */ +#define USE_SAO_SMALL_BUFFER /* reduce the memory used by SAO */ +//#define USE_PRED /* allow non intra frames */ +//#define USE_FULL /* include HEVC code not relevant for BPG decoding */ +//#define USE_FUNC_PTR /* use function pointers for dsp */ +//#define USE_AV_LOG /* include av_log() */ + +#endif /* FFMPEG_CONFIG_H */ diff --git a/doc/bpg_spec.txt b/doc/bpg_spec.txt new file mode 100644 index 0000000..6e0d646 --- /dev/null +++ b/doc/bpg_spec.txt @@ -0,0 +1,426 @@ +BPG Specification + +version 0.9.3 + +Copyright (c) 2014 Fabrice Bellard + +1) Introduction +--------------- + +BPG is a lossy and lossless picture compression format based on HEVC +[1]. It supports grayscale, YCbCr, RGB, YCgCo color spaces with an +optional alpha channel. CMYK is supported by reusing the alpha channel +to encode an additional white component. The bit depth of each +component is from 8 to 14 bits. The color values are stored either in +full range (JPEG case) or limited range (video case). The YCbCr color +space is either BT 601 (JPEG case), BT 709 or BT 2020. + +The chroma can be subsampled by a factor of two in horizontal or both +in horizontal and vertical directions (4:4:4, 4:2:2 or 4:2:0 chroma +formats are supported). The chroma is sampled at the same position +relative to the luma as in the JPEG format [2]. + +Arbitrary metadata (such as EXIF, ICC profile, XMP) are supported. + +2) Bitstream conventions +------------------------ + +The bit stream is byte aligned and bit fields are read from most +significant to least signficant bit in each byte. + +- u(n) is an unsigned integer stored on n bits. + +- ue7(n) is an unsigned integer of at most n bits stored on a variable + number of bytes. All the bytes except the last one have a '1' as + their first bit. The unsigned integer is represented as the + concatenation of the remaining 7 bit codewords. Only the shortest + encoding for a given unsigned integer shall be accepted by the + decoder (i.e. the first byte is never 0x80). Example: + + Encoded bytes Unsigned integer value + 0x08 8 + 0x84 0x1e 542 + 0xac 0xbe 0x17 728855 + +- ue(v) : unsigned integer 0-th order Exp-Golomb-coded (see HEVC + specification). + +- b(8) is an arbitrary byte. + +3) File format +-------------- + +3.1) Syntax +----------- + +heic_file() { + + file_magic u(32) + + pixel_format u(3) + alpha1_flag u(1) + bit_depth_minus_8 u(4) + + color_space u(4) + extension_present_flag u(1) + alpha2_flag u(1) + limited_range_flag u(1) + reserved_zero u(1) + + picture_width ue7(32) + picture_height ue7(32) + + picture_data_length ue7(32) + if (extension_present_flag) + extension_data_length ue7(32) + if (alpha1_flag || alpha2_flag) + alpha_data_length ue7(32) + + if (extension_present_flag) { + extension_data() + } + + hevc_header_and_data() + + if (alpha1_flag || alpha2_flag) { + hevc_header_and_data() + } + +} + +extension_data() +{ + for(i = 0; i < v; i++) { + extension_tag ue7(32) + extension_tag_length ue7(32) + for(j = 0; j < extension_tag_length; j++) { + extension_tag_data_byte b(8) + } + } +} + +hevc_header_and_data() +{ + hevc_header_length ue7(32) + log2_min_luma_coding_block_size_minus3 ue(v) + log2_diff_max_min_luma_coding_block_size ue(v) + log2_min_transform_block_size_minus2 ue(v) + log2_diff_max_min_transform_block_size ue(v) + max_transform_hierarchy_depth_intra ue(v) + sample_adaptive_offset_enabled_flag u(1) + pcm_enabled_flag u(1) + if (pcm_enabled_flag) { + pcm_sample_bit_depth_luma_minus1 u(4) + pcm_sample_bit_depth_chroma_minus1 u(4) + log2_min_pcm_luma_coding_block_size_minus3 ue(v) + log2_diff_max_min_pcm_luma_coding_block_size ue(v) + pcm_loop_filter_disabled_flag u(1) + } + strong_intra_smoothing_enabled_flag u(1) + sps_extension_present_flag u(1) + if (sps_extension_present_flag) { + sps_range_extension_flag u(1) + sps_extension_7bits u(7) + } + if (sps_range_extension_flag) { + transform_skip_rotation_enabled_flag u(1) + transform_skip_context_enabled_flag u(1) + implicit_rdpcm_enabled_flag u(1) + explicit_rdpcm_enabled_flag u(1) + extended_precision_processing_flag u(1) + intra_smoothing_disabled_flag u(1) + high_precision_offsets_enabled_flag u(1) + persistent_rice_adaptation_enabled_flag u(1) + cabac_bypass_alignment_enabled_flag u(1) + } + trailing_bits u(v) + + hevc_data() +} + +hevc_data() +{ + for(i = 0; i < v; i++) { + hevc_data_byte b(8) + } +} + + +3.2) Semantics +-------------- + + 'file_magic' is defined as 0x425047fb. + + 'pixel_format' indicates the chroma subsampling: + + 0 : Grayscale + 1 : 4:2:0 + 2 : 4:2:2 + 3 : 4:4:4 + + The other values are reserved. + + The chroma samples in the 4:2:0 and 4:2:2 formats are sampled + at the same position as JPEG [2]. + + 'alpha1_flag' and 'alpha2_flag' give information about the alpha plane: + + alpha1_flag=0 alpha2_flag=0: no alpha plane. + + alpha1_flag=1 alpha2_flag=0: alpha present. The color is not + premultiplied. + + alpha1_flag=1 alpha2_flag=1: alpha present. The color is + premultiplied. The resulting non-premultiplied R', G', B' shall + be recovered as: + + if A != 0 + R' = min(R / A, 1), G' = min(G / A, 1), B' = min(B / A, 1) + else + R' = G' = B' = 1 . + + alpha1_flag=0 alpha2_flag=1: the alpha plane is present and + contains the W color component (CMYK color). The resulting CMYK + data can be recovered as follows: + + C = (1 - R), M = (1 - G), Y = (1 - B), K = (1 - W) . + + In case no color profile is specified, the sRGB color R'G'B' + shall be computed as: + + R' = R * W, G' = G * W, B' = B * W . + + 'bit_depth_minus_8' is the number of bits used for each component + minus 8. In this version of the specification, bit_depth_minus_8 + <= 6. + + 'extension_present_flag' indicates that extension data are + present. + + 'color_space' specifies how to convert the color planes to + RGB. It must be 0 when pixel_format = 0 (grayscale): + + 0 : YCbCr (BT 601, same as JPEG and HEVC matrix_coeffs = 5) + 1 : RGB (component order: G B R) + 2 : YCgCo (same as HEVC matrix_coeffs = 8) + 3 : YCbCr (BT 709, same as HEVC matrix_coeffs = 1) + 4 : YCbCr (BT 2020 non constant luminance system, same as HEVC + matrix_coeffs = 9) + 5 : reserved for BT 2020 constant luminance system, not + supported in this version of the specification. + + The other values are reserved. + + YCbCr is defined using the BT 601, BT 709 or BT 2020 conversion + matrices. + + For RGB, G is stored as the Y plane. B in the Cb plane and R in + the Cr plane. + + YCgCo is defined as HEVC matrix_coeffs = 8, full range. Y is + stored in the Y plane. Cg in the Cb plane and Co in the Cr + plane. + + If no color profile is present, the RGB output data are assumed + to be in the sRGB color space [6]. + + 'limited_range_flag': opposite of the HEVC video_full_range_flag. + The value zero indicates that the full range of each color + component is used. The value one indicates that a limited range + is used: + + - (16 << (bit_depth - 8) to (235 << (bit_depth - 8)) for Y + and G, B, R, + - (16 << (bit_depth - 8) to (240 << (bit_depth - 8)) for Cb and Cr. + + For the YCgCo color space, the range limitation shall be done on + the RGB data. + + The alpha (or W) plane always uses the full range. + + 'reserved_zero' must be 0 in this version. + + 'picture_width' is the picture width in pixels. The value 0 is + not allowed. + + 'picture_height' is the picture height in pixels. The value 0 is + not allowed. + + 'picture_data_length' is the picture data length in bytes. + + 'extension_data_length' is the extension data length in bytes. + + 'alpha_data_length' is the alpha data length in bytes. + + 'extension_data()' is the extension data. + + 'extension_tag' is the extension tag. The following values are defined: + + 1: EXIF data. + + 2: ICC profile (see [4]) + + 3: XMP (see [5]) + + 4: Thumbnail (the thumbnail shall be a lower resolution version + of the image and stored in BPG format). + + The decoder shall ignore the tags it does not support. + + 'extension_tag_length' is the length in bytes of the extension tag. + + 'hevc_header_length' is the length in bytes of the following data + up to and including 'trailing_bits'. + + 'log2_min_luma_coding_block_size_minus3', + 'log2_diff_max_min_luma_coding_block_size', + 'log2_min_transform_block_size_minus2', + 'log2_diff_max_min_transform_block_size', + 'max_transform_hierarchy_depth_intra', + 'sample_adaptive_offset_enabled_flag', 'pcm_enabled_flag', + 'pcm_sample_bit_depth_luma_minus1', + 'pcm_sample_bit_depth_chroma_minus1', + 'log2_min_pcm_luma_coding_block_size_minus3', + 'log2_diff_max_min_pcm_luma_coding_block_size', + 'pcm_loop_filter_disabled_flag', + 'strong_intra_smoothing_enabled_flag', 'sps_extension_flag' + 'sps_extension_present_flag', 'sps_range_extension_flag' + 'transform_skip_rotation_enabled_flag', + 'transform_skip_context_enabled_flag', + 'implicit_rdpcm_enabled_flag', 'explicit_rdpcm_enabled_flag', + 'extended_precision_processing_flag', + 'intra_smoothing_disabled_flag', + 'high_precision_offsets_enabled_flag', + 'persistent_rice_adaptation_enabled_flag', + 'cabac_bypass_alignment_enabled_flag' are + the corresponding fields of the HEVC SPS syntax element. + + 'trailing_bits' has a value of 0 and has a length from 0 to 7 + bits so that the next data is byte aligned. + + 'hevc_data()' contains the corresponding HEVC picture data, + excluding the first NAL start code (i.e. the first 0x00 0x00 0x01 + or 0x00 0x00 0x00 0x01 bytes). The VPS and SPS NALs shall not be + included in the HEVC picture data. The decoder can recover the + necessary fields from the header by doing the following + assumptions: + + - vps_video_parameter_set_id = 0 + - sps_video_parameter_set_id = 0 + - sps_max_sub_layers = 1 + - sps_seq_parameter_set_id = 0 + - chroma_format_idc: for picture data: + chroma_format_idc = pixel_format + for alpha data: + chroma_format_idc = 0. + - separate_colour_plane_flag = 0 + - pic_width_in_luma_samples = ceil(picture_width/cb_size) * cb_size + - pic_height_in_luma_samples = ceil(picture_height/cb_size) * cb_size + with cb_size = 1 << log2_min_luma_coding_block_size + - bit_depth_luma_minus8 = bit_depth_minus_8 + - bit_depth_chroma_minus8 = bit_depth_minus_8 + - scaling_list_enabled_flag = 0 + +3.3) HEVC Profile +----------------- + +Conforming HEVC bit streams shall conform to the Main 4:4:4 16 Still +Picture, Level 8.5 of the HEVC specification with the following +modifications. + +- separate_colour_plane_flag shall be 0 when present. + +- bit_depth_luma_minus8 <= 6 + +- bit_depth_chroma_minus8 = bit_depth_luma_minus8 + +- explicit_rdpcm_enabled_flag = 0 (does not matter for intra frames) + +- extended_precision_processing_flag = 0 + +- cabac_bypass_alignment_enabled_flag = 0 + +- high_precision_offsets_enabled_flag = 0 (does not matter for intra frames) + +- If the encoded image is larger than the size indicated by +picture_width and picture_height, the lower right part of the decoded +image shall be cropped. If a horizontal (resp. vertical) decimation by +two is done for the chroma and that the width (resp. height) is n +pixels, ceil(n/2) pixels must be kept as the resulting chroma +information. + +4) Design choices +----------------- + +(This section is informative) + +- Our design principle was to keep the format as simple as possible + while taking the HEVC codec as basis. Our main metric to evaluate + the simplicity was the size of a software decoder which outputs 32 + bit RGBA pixel data. + +- Pixel formats: we wanted to be able to convert JPEG images to BPG + with as little loss as possible. So supporting the same color space + (CCIR 601 YCbCr) with the same range (full range) and most of the + allowed JPEG chroma formats (4:4:4, 4:2:2, 4:2:0 or grayscale) was + mandatory to avoid going back to RGB or doing a subsampling or + interpolation. + +- Alpha support: alpha support is mandatory. We chose to use a + separate HEVC monochrome plane to handle it instead of another + format to simplify the decoder. The color is either + non-premultiplied or premultiplied. Premultiplied alpha usually + gives a better compression. Non-premultiplied alpha is supported in + case no loss is needed on the color components. + +- Color spaces: In addition to YCbCr, RGB is supported for the high + quality or lossless cases. YCgCo is supported because it may give + slightly better results than YCbCr for high quality images. CMYK is + supported so that JPEGs containing this color space can be + converted. The alpha plane is used to store the W (1-K) plane. The + data is stored with inverted components (1-X) so that the conversion + to RGB is simplified. The support of the BT 709 and BT 2020 (non + constant luminance) YCbCr encodings and of the limited range color + values were added to reduce the losses when converting video frames. + +- Bit depth: we decided to support the HEVC bit depths 8 to 14. The + added complexity is small and it allows to support high quality + pictures from cameras. + +- Picture file format: keeping a completely standard HEVC stream would + have meant a more difficult parsing for the picture header which is + a problem for the various image utilities to get the basic picture + information (pixel format, width, height). So we added a small + header before the HEVC bit stream. The picture header is byte + oriended so it is easy to parse. + +- HEVC bit stream: the standard HEVC headers (the VPS and SPS NALs) + give an overhead of about 60 bytes for no added value in the case of + picture compression. Since the alpha plane uses a different HEVC bit + stream, it also adds the same overhead again. So we removed the VPS + and SPS NALs and added a very small header with the equivalent + information (typically 4 bytes). We also removed the first NAL start + code which is not useful. It is still possible to reconstruct a + standard HEVC stream to feed an unmodified hardware decoder if needed. + +- Extensions: the metadata are stored at the beginning of the file so + that they can be read at the same time as the header. Since metadata + tend to evolve faster than the image formats, we left room for + extension by using a (tag, lengh) representation. The decoder can + easily skip all the metadata because their length is explicitly + stored in the image header. + +5) References +------------- + +[1] High efficiency video coding (HEVC) version 2 (ITU-T Recommendation H.265) + +[2] JPEG File Interchange Format version 1.02 ( http://www.w3.org/Graphics/JPEG/jfif3.pdf ) + +[3] EXIF version 2.2 (JEITA CP-3451) + +[4] The International Color Consortium ( http://www.color.org/ ) + +[5] Extensible Metadata Platform (XMP) http://www.adobe.com/devnet/xmp.html + +[6] sRGB color space, IEC 61966-2-1. diff --git a/html/bpgdec.js b/html/bpgdec.js new file mode 100644 index 0000000..b247759 --- /dev/null +++ b/html/bpgdec.js @@ -0,0 +1,91 @@ +function b(a){throw a;}var h=void 0,i=!0,k=null,l;l||(l=eval("(function() { try { return Module || {} } catch(e) { return {} } })()"));var r={},t;for(t in l)l.hasOwnProperty(t)&&(r[t]=l[t]);var u="object"===typeof process&&"function"===typeof require,v="object"===typeof window,aa="function"===typeof importScripts,w=!v&&!u&&!aa; +if(u){l.print||(l.print=function(a){process.stdout.write(a+"\n")});l.printErr||(l.printErr=function(a){process.stderr.write(a+"\n")});var ba=require("fs"),ca=require("path");l.read=function(a,d){var a=ca.normalize(a),c=ba.readFileSync(a);!c&&a!=ca.resolve(a)&&(a=path.join(__dirname,"..","src",a),c=ba.readFileSync(a));c&&!d&&(c=c.toString());return c};l.readBinary=function(a){return l.read(a,i)};l.load=function(a){da(read(a))};l.thisProgram=process.argv[1].replace(/\\/g,"/");l.arguments=process.argv.slice(2); +"undefined"!==typeof module&&(module.exports=l);process.on("uncaughtException",function(a){a instanceof ea||b(a)})}else w?(l.print||(l.print=print),"undefined"!=typeof printErr&&(l.printErr=printErr),l.read="undefined"!=typeof read?read:function(){b("no read() available (jsc?)")},l.readBinary=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");x("object"===typeof a);return a},"undefined"!=typeof scriptArgs?l.arguments=scriptArgs:"undefined"!=typeof arguments&& +(l.arguments=arguments),this.Module=l,eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined")):v||aa?(l.read=function(a){var d=new XMLHttpRequest;d.open("GET",a,!1);d.send(k);return d.responseText},"undefined"!=typeof arguments&&(l.arguments=arguments),"undefined"!==typeof console?(l.print||(l.print=function(a){console.log(a)}),l.printErr||(l.printErr=function(a){console.log(a)})):l.print||(l.print=function(){}),v?window.Module=l:l.load=importScripts): +b("Unknown runtime environment. Where are we?");function da(a){eval.call(k,a)}!l.load&&l.read&&(l.load=function(a){da(l.read(a))});l.print||(l.print=function(){});l.printErr||(l.printErr=l.print);l.arguments||(l.arguments=[]);l.thisProgram||(l.thisProgram="./this.program");l.print=l.print;l.a=l.printErr;l.preRun=[];l.postRun=[];for(t in r)r.hasOwnProperty(t)&&(l[t]=r[t]); +var z={M:function(a){fa=a},J:function(){return fa},m:function(){return y},q:function(a){y=a},o:function(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?z.f:"i"===a[0]?(a=parseInt(a.substr(1)),x(0===a%8),a/8):0}},I:function(a){return Math.max(z.o(a),z.f)},O:16,Y:function(a,d,c){return!c&&("i64"==a||"double"==a)?8:!a?Math.min(d,8):Math.min(d||(a?z.I(a):0),z.f)},j:function(a, +d,c){return c&&c.length?(c.splice||(c=Array.prototype.slice.call(c)),c.splice(0,0,d),l["dynCall_"+a].apply(k,c)):l["dynCall_"+a].call(k,d)},c:[],t:function(a){for(var d=0;d=E&&A("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+E+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.");return d},g:function(a,d){return Math.ceil(a/(d?d:16))*(d?d:16)},da:function(a,d,c){return c?+(a>>>0)+4294967296*+(d>>>0):+(a>>>0)+4294967296*+(d|0)},r:8,f:4,P:0}; +l.Runtime=z;z.addFunction=z.t;z.removeFunction=z.L;var F=!1,G,ga,fa;function x(a,d){a||A("Assertion failed: "+d)}function ha(a){var d=l["_"+a];if(!d)try{d=eval("_"+a)}catch(c){}x(d,"Cannot call unknown function "+a+" (perhaps LLVM optimizations or closure removed it?)");return d}var ia,ja; +(function(){function a(a){a=a.toString().match(f).slice(1);return{arguments:a[0],body:a[1],returnValue:a[2]}}var d=0,c={stackSave:function(){d=z.m()},stackRestore:function(){z.q(d)},arrayToC:function(a){var c=z.d(a.length);ka(a,c);return c},stringToC:function(a){var c=0;a!==k&&(a!==h&&0!==a)&&(c=z.d((a.length<<2)+1),la(a,c));return c}},e={string:c.stringToC,array:c.arrayToC};ja=function(a,f,g,j){var a=ha(a),q=[];if(j)for(var n=0;n>0]=d;break;case "i8":H[a>>0]=d;break;case "i16":I[a>>1]=d;break;case "i32":J[a>>2]=d;break;case "i64":ga=[d>>>0,(G=d,1<=+na(G)?0>>0:~~+qa((G-+(~~G>>>0))/4294967296)>>>0:0)];J[a>>2]=ga[0];J[a+4>>2]=ga[1];break;case "float":N[a>>2]=d;break;case "double":O[a>>3]=d;break;default:A("invalid type for setValue: "+c)}}l.setValue=ma; +l.getValue=function(a,d){d=d||"i8";"*"===d.charAt(d.length-1)&&(d="i32");switch(d){case "i1":return H[a>>0];case "i8":return H[a>>0];case "i16":return I[a>>1];case "i32":return J[a>>2];case "i64":return J[a>>2];case "float":return N[a>>2];case "double":return O[a>>3];default:A("invalid type for setValue: "+d)}return k};var ra=2,ta=4;l.ALLOC_NORMAL=0;l.ALLOC_STACK=1;l.ALLOC_STATIC=ra;l.ALLOC_DYNAMIC=3;l.ALLOC_NONE=ta; +function P(a,d,c,e){var f,g;"number"===typeof a?(f=i,g=a):(f=!1,g=a.length);var j="string"===typeof d?d:k,c=c==ta?e:[ua,z.d,z.N,z.b][c===h?ra:c](Math.max(g,j?1:d.length));if(f){e=c;x(0==(c&3));for(a=c+(g&-4);e>2]=0;for(a=c+g;e>0]=0;return c}if("i8"===j)return a.subarray||a.slice?Q.set(a,c):Q.set(new Uint8Array(a),c),c;for(var e=0,m,p;eS?2*S:S+16777216;S!==E&&(l.a("increasing TOTAL_MEMORY to "+S+" to be compliant with the asm.js spec"),E=S); +x("undefined"!==typeof Int32Array&&"undefined"!==typeof Float64Array&&!!(new Int32Array(1)).subarray&&!!(new Int32Array(1)).set,"JS engine does not provide full typed array support");var T=new ArrayBuffer(E);H=new Int8Array(T);I=new Int16Array(T);J=new Int32Array(T);Q=new Uint8Array(T);wa=new Uint16Array(T);xa=new Uint32Array(T);N=new Float32Array(T);O=new Float64Array(T);J[0]=255;x(255===Q[0]&&0===Q[3],"Typed arrays 2 must be run on a little-endian system");l.HEAP=h;l.buffer=T;l.HEAP8=H; +l.HEAP16=I;l.HEAP32=J;l.HEAPU8=Q;l.HEAPU16=wa;l.HEAPU32=xa;l.HEAPF32=N;l.HEAPF64=O;function U(a){for(;0>0]=a[c],c+=1}l.writeStringToMemory=la;function ka(a,d){for(var c=0;c>0]=a[c]}l.writeArrayToMemory=ka; +l.writeAsciiToMemory=function(a,d,c){for(var e=0;e>0]=a.charCodeAt(e);c||(H[d+a.length>>0]=0)};if(!Math.imul||-5!==Math.imul(4294967295,5))Math.imul=function(a,d){var c=a&65535,e=d&65535;return c*e+((a>>>16)*e+c*(d>>>16)<<16)|0};Math.ca=Math.imul;var na=Math.abs,qa=Math.ceil,pa=Math.floor,oa=Math.min,V=0,La=k,W=k;function Ma(){V++;l.monitorRunDependencies&&l.monitorRunDependencies(V)}l.addRunDependency=Ma; +function Na(){V--;l.monitorRunDependencies&&l.monitorRunDependencies(V);if(0==V&&(La!==k&&(clearInterval(La),La=k),W)){var a=W;W=k;a()}}l.removeRunDependency=Na;l.preloadedImages={};l.preloadedAudios={};var X=k,R=8,B=R+6112;Da.push(); +P([0,0,1,0,1,2,0,1,2,3,1,2,3,2,3,3,0,1,0,2,1,0,3,2,1,0,3,2,1,3,2,3,0,0,1,0,1,2,0,1,2,3,0,1,2,3,4,0,1,2,3,4,5,0,1,2,3,4,5,6,0,1,2,3,4,5,6,7,1,2,3,4,5,6,7,2,3,4,5,6,7,3,4,5,6,7,4,5,6,7,5,6,7,6,7,7,0,1,0,2,1,0,3,2,1,0,4,3,2,1,0,5,4,3,2,1,0,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,7,6,5,4,3,2,7,6,5,4,3,7,6,5,4,7,6,5,7,6,7,40,45,51,57,64,72,0,0,29,0,0,0,30,0,0,0,31,0,0,0,32,0,0,0,33,0,0,0,33,0,0,0,34,0,0,0,34,0,0,0,35,0,0,0,35,0,0,0,36,0,0,0,36,0,0,0,37,0,0,0,37,0,0,0,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2, +3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,11,11,11,12,12,0,0,0,0,0,0,0,2,5,9,1,4,8,12,3,7,11,14,6,10,13,15,0,0,0,0,0,0,0,0,0,2,1,3,0,0,0,0,0,2,5,9,14,20,27,35,1,4,8,13,19,26,34,42,3,7,12,18,25,33,41,48,6,11,17,24,32,40,47,53,10,16,23,31,39,46,52,57,15,22,30,38,45,51, +56,60,21,29,37,44,50,55,59,62,28,36,43,49,54,58,61,63,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,0,1,2,3,16,17,18,19,4,5,6,7,20,21,22,23,8,9,10,11,24,25,26,27,12,13,14,15,28,29,30,31,32,33,34,35,48,49,50,51,36,37,38,39,52,53,54,55,40,41,42,43,56,57,58,59,44,45,46,47,60,61,62,63,0,1,4,5,2,3,4,5,6,6,8,8,7,7,8,8,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,2,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,2,1,0,0,2,1,0,0,2,1,0,0,2,1,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,153,200,139, +141,157,154,154,154,154,154,154,154,154,184,154,154,154,184,63,139,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,153,138,138,111,141,94,138,182,154,139,139,139,139,139,139,110,110,124,125,140,153,125,127,140,109,111,143,127,111,79,108,123,63,110,110,124,125,140,153,125,127,140,109,111,143,127,111,79,108,123,63,91,171,134,141,111,111,125,110,110,94,124,108,124,107,125,141,179,153,125,107,125,141,179,153,125,107,125,141,179,153,125,140,139,182,182,152,136,152,136,153,136,139,111, +136,139,111,141,111,140,92,137,138,140,152,138,139,153,74,149,92,139,107,122,152,140,179,166,182,140,227,122,197,138,153,136,167,152,152,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,185,107,139,126,154,197,185,201,154,154,154,149,154,139,154,154,154,152,139,110,122,95,79,63,31,31,153,153,153,153,140,198,140,198,168,79,124,138,94,153,111,149,107,167,154,139,139,139,139,139,139,125,110,94,110,95,79,125,111,110,78,110,111,111,95,94,108,123,108,125,110, +94,110,95,79,125,111,110,78,110,111,111,95,94,108,123,108,121,140,61,154,155,154,139,153,139,123,123,63,153,166,183,140,136,153,154,166,183,140,136,153,154,166,183,140,136,153,154,170,153,123,123,107,121,107,121,167,151,183,140,151,183,140,140,140,154,196,196,167,154,152,167,182,182,134,149,136,153,121,136,137,169,194,166,167,154,167,137,182,107,167,91,122,107,167,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,160,107,139,126,154,197,185,201,154,154, +154,134,154,139,154,154,183,152,139,154,137,95,79,63,31,31,153,153,153,153,169,198,169,198,168,79,224,167,122,153,111,149,92,167,154,139,139,139,139,139,139,125,110,124,110,95,94,125,111,111,79,125,126,111,111,79,108,123,93,125,110,124,110,95,94,125,111,111,79,125,126,111,111,79,108,123,93,121,140,61,154,170,154,139,153,139,123,123,63,124,166,183,140,136,153,154,166,183,140,136,153,154,166,183,140,136,153,154,170,153,138,138,122,121,122,121,167,151,183,140,151,183,140,140,140,154,196,167,167,154, +152,167,182,182,134,149,136,153,121,136,122,169,208,166,167,154,152,167,182,107,167,91,107,107,167,154,154,154,154,154,154,154,154,154,154,154,154,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,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,10,11,13,14,16,18,20,22,24,0,0,29,30,31,32,33,33,34,34,35,35,36,36,37,37, +0,0,104,101,118,99,0,0,0,0,128,5,0,0,0,0,0,0,0,0,0,0,53,54,50,72,34,48,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,172,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,10,1,0,0,0,0,0,1,2,2,2,2,3,5,7,8,10,12,13,15,17,18,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,31,0,0,0,0,0,7,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,32,26,21,17,13,9,5,2,0,254,251,247,243,239,235,230,224,230,235,239,243,247,251,254,0, +2,5,9,13,17,21,26,32,0,0,0,0,0,0,0,0,240,154,249,114,252,138,253,30,254,122,254,197,254,0,255,197,254,122,254,30,254,138,253,114,252,154,249,0,240,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,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,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,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,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,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,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,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,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,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,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,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,64,90,90,90,89,88,87,85,83,82,80,78,75,73,70,67,64,61,57,54,50,46,43,38,36,31,25,22,18,13,9,4,1,2,0,3,4,0,0,0,255,0,1,0,0,255,0,1,255,255,1,1,1,255,255,1,16,16,16,16,17,18,21,24,16,16,16,16,17,19,22,25,16,16,17,18,20,22,25,29,16,16,18,21,24,27,31,36,17,17,20,24,30,35,41,47,18,19,22,27,35,44,54,65,21,22,25,31, +41,54,70,88,24,25,29,36,47,65,88,115,16,16,16,16,17,18,20,24,16,16,16,17,18,20,24,25,16,16,17,18,20,24,25,28,16,17,18,20,24,25,28,33,17,18,20,24,25,28,33,41,18,20,24,25,28,33,41,54,20,24,25,28,33,41,54,71,24,25,28,33,41,54,71,91,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0,255,255,255,127,0,0,0,0,0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7, +7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,54,0,0,0,0,0,0,0,3,1,1,0,36,120,37,120,38,120,0,0,0,0,0,0,56,0,0,0,0,0,0,0,3,1,0,16,36,120,37,120,38,120,0,0,0,0,0,0,58,0,0,0,0,0,0,0,3,0,0,16,36,120,37,120,38,120,0,0,0,0,0,0,32,0,0,0,0,0,0,0,1,0,0,0,36,120,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,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,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,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,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,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,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,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,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,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,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,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,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,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],"i8",ta,z.r);var Oa=z.g(P(12,"i8",ra),8);x(0==Oa%8);l._llvm_bswap_i32=Pa;l._bitshift64Ashr=Qa;l._i64Subtract=Ra;function Y(a){Y.G||(C=C+4095&-4096,Y.G=i,x(z.b),Y.u=z.b,z.b=function(){A("cannot dynamically allocate, sbrk now has control")});var d=C;0!=a&&Y.u(a);return d}l._i64Add=Sa;l._strlen=Ta;l._memset=Ua;l._bitshift64Shl=Va;function Wa(a){l.exit(a)} +function Xa(a){return 0.5!==Math.abs(a%1)?Math.round(a):a+a%2+(0>a?1:-1)}l._memcpy=Ya;ya=y=z.g(B);za=ya+Ba;Aa=C=z.g(za);x(Aa>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function Sa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function Ta(a){a=a|0;D=a}function Ua(){return D|0}function Va(b,d){b=b|0;d=d|0;var e=0,f=0;e=i;if(!(a[(c[b+204>>2]|0)+43>>0]|0)){i=e;return}f=c[(c[b+200>>2]|0)+13128>>2]|0;d=(d|0)%(f|0)|0;if((d|0)!=2?!((f|0)==2&(d|0)==0):0){i=e;return}ce(c[b+152>>2]|0,c[b+136>>2]|0,199)|0;i=e;return}function Wa(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;g=b+204|0;f=c[g>>2]|0;if((c[(c[f+1668>>2]|0)+(c[b+2500>>2]<<2)>>2]|0)==(d|0)){Xa(b);f=b+1449|0;if(a[f>>0]|0){j=c[g>>2]|0;if((a[j+42>>0]|0)!=0?(j=c[j+1676>>2]|0,(c[j+(d<<2)>>2]|0)!=(c[j+(d+ -1<<2)>>2]|0)):0)h=5}else h=5;if((h|0)==5)Ya(b);if(a[b+1448>>0]|0){i=e;return}if(!(a[(c[g>>2]|0)+43>>0]|0)){i=e;return}g=c[(c[b+200>>2]|0)+13128>>2]|0;if((d|0)%(g|0)|0){i=e;return}if((g|0)==1){Ya(b);i=e;return}if((a[f>>0]|0)!=1){i=e;return}ce(c[b+136>>2]|0,c[b+152>>2]|0,199)|0;i=e;return}if((a[f+42>>0]|0)!=0?(j=c[f+1676>>2]|0,(c[j+(d<<2)>>2]|0)!=(c[j+(d+ -1<<2)>>2]|0)):0){if((a[b+141>>0]|0)==1)Za(c[b+136>>2]|0);else Xa(b);Ya(b);f=c[g>>2]|0}if(!(a[f+43>>0]|0)){i=e;return}f=b+200|0;if((d|0)%(c[(c[f>>2]|0)+13128>>2]|0)|0){i=e;return}d=b+136|0;_a((c[d>>2]|0)+224|0)|0;if((a[b+141>>0]|0)==1)Za(c[d>>2]|0);else Xa(b);if((c[(c[f>>2]|0)+13128>>2]|0)==1){Ya(b);i=e;return}else{ce(c[d>>2]|0,c[b+152>>2]|0,199)|0;i=e;return}}function Xa(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;e=a+136|0;a=c[e>>2]|0;d=a+204|0;cd(d,1);g=a+212|0;f=c[g>>2]|0;h=0-f&7;if(h){cd(d,h);f=c[g>>2]|0}_c((c[e>>2]|0)+224|0,(c[d>>2]|0)+((f|0)/8|0)|0,(7-f+(c[a+216>>2]|0)|0)/8|0);i=b;return}function Ya(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;g=i;f=c[b+1440>>2]|0;e=2-f|0;e=(a[b+2060>>0]|0)==0|(f|0)==2?e:e^3;f=b+2112|0;b=b+136|0;h=0;do{j=d[680+(e*199|0)+h>>0]|0;l=a[f>>0]|0;k=l<<24>>24;if(l<<24>>24<0)k=0;else k=(k|0)>51?51:k;j=((j<<3&120)+ -16+(($(k,((j>>>4)*5|0)+ -45|0)|0)>>4)<<1)+ -127|0;j=j>>31^j;if((j|0)>124)j=j&1|124;a[(c[b>>2]|0)+h>>0]=j;h=h+1|0}while((h|0)!=199);a[(c[b>>2]|0)+199>>0]=0;a[(c[b>>2]|0)+200>>0]=0;a[(c[b>>2]|0)+201>>0]=0;a[(c[b>>2]|0)+202>>0]=0;i=g;return}function Za(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;d=a+224|0;e=c[a+240>>2]|0;f=c[d>>2]|0;e=(f&1|0)==0?e:e+ -1|0;e=(f&511|0)==0?e:e+ -1|0;a=(c[a+244>>2]|0)-e|0;if((a|0)<0){i=b;return}_c(d,e,a);i=b;return}function _a(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;f=a+4|0;d=c[f>>2]|0;e=d+ -2|0;c[f>>2]=e;g=c[a>>2]|0;if((g|0)>=(e<<17|0)){g=(c[a+16>>2]|0)-(c[a+12>>2]|0)|0;i=b;return g|0}d=(d+ -258|0)>>>31;c[f>>2]=e<>2]=g;if(g&65535){g=0;i=b;return g|0}Ab(a);g=0;i=b;return g|0}function $a(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a)|0;i=b;return a|0}function ab(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;h=d[e>>0]|0;j=b+4|0;k=c[j>>2]|0;l=d[2880+((k<<1&384)+(h|512))>>0]|0;k=k-l|0;m=k<<17;n=c[b>>2]|0;g=m-n>>31;c[b>>2]=n-(g&m);c[j>>2]=(g&l-k)+k;h=g^h;a[e>>0]=a[h+4032>>0]|0;e=h&1;h=c[j>>2]|0;g=d[2880+h>>0]|0;c[j>>2]=h<>2]<>2]=g;if(g&65535){i=f;return e|0}j=b+16|0;h=c[j>>2]|0;c[b>>2]=(((d[h+1>>0]|0)<<1|(d[h>>0]|0)<<9)+ -65535<<7-(d[2880+((g+ -1^g)>>15)>>0]|0))+g;if(h>>>0>=(c[b+20>>2]|0)>>>0){i=f;return e|0}c[j>>2]=h+2;i=f;return e|0}function bb(a){a=a|0;var b=0,d=0;b=i;a=a+136|0;d=c[a>>2]|0;if(!(ab(d+224|0,d+1|0)|0)){d=0;i=b;return d|0}d=(cb((c[a>>2]|0)+224|0)|0)==0;d=d?1:2;i=b;return d|0}function cb(a){a=a|0;var b=0,d=0,e=0;b=i;d=c[a>>2]<<1;c[a>>2]=d;if(!(d&65534)){Ab(a);d=c[a>>2]|0}e=c[a+4>>2]<<17;if((d|0)<(e|0)){e=0;i=b;return e|0}c[a>>2]=d-e;e=1;i=b;return e|0}function db(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function eb(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;d=c[(c[a+200>>2]|0)+52>>2]|0;d=(d|0)>10?31:(1<0)a=0;else{f=0;i=b;return f|0}while(1){f=a+1|0;if(!(cb((c[e>>2]|0)+224|0)|0)){d=4;break}if((f|0)<(d|0))a=f;else{a=f;d=4;break}}if((d|0)==4){i=b;return a|0}return 0}function fb(a){a=a|0;var b=0;b=i;a=cb((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function gb(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function hb(a){a=a|0;var b=0;b=i;a=_a((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function ib(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+5|0)|0;i=b;return a|0}function jb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;a=a+136|0;g=9;e=0;while(1){h=c[a>>2]|0;f=e;e=e+1|0;if(!(ab(h+224|0,h+g|0)|0)){e=f;g=0;break}if((e|0)>=5){f=0;g=0;d=4;break}else g=10}do if((d|0)==4){while(1){d=0;if(!(cb((c[a>>2]|0)+224|0)|0)){d=5;break}g=(1<>2]|0)+224|0)|0)<>2]|0)+224|0)|0;i=b;return a|0}function lb(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+176|0)|0;i=b;return a|0}function mb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;e=a[(c[b+204>>2]|0)+1633>>0]|0;e=(e&255)<5?5:e&255;f=b+136|0;if(!e){g=0;i=d;return g|0}else b=0;while(1){h=c[f>>2]|0;g=b+1|0;if(!(ab(h+224|0,h+177|0)|0)){e=4;break}if((g|0)<(e|0))b=g;else{b=g;e=4;break}}if((e|0)==4){i=d;return b|0}return 0}function nb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0;j=i;k=c[b+200>>2]|0;n=(1<>2])+ -1|0;l=n&g;m=c[k+13064>>2]|0;h=f>>m;m=g>>m;g=c[b+136>>2]|0;if((a[g+308>>0]|0)==0?(n&f|0)==0:0)f=0;else{f=h+ -1+($(c[k+13140>>2]|0,m)|0)|0;f=d[(c[b+4336>>2]|0)+f>>0]|0}if((a[g+309>>0]|0)==0&(l|0)==0){n=0;m=(f|0)>(e|0);m=m&1;n=(n|0)>(e|0);n=n&1;f=g+224|0;m=m|2;n=m+n|0;n=g+n|0;n=ab(f,n)|0;i=j;return n|0}n=($(c[k+13140>>2]|0,m+ -1|0)|0)+h|0;n=d[(c[b+4336>>2]|0)+n>>0]|0;m=(f|0)>(e|0);m=m&1;n=(n|0)>(e|0);n=n&1;f=g+224|0;m=m|2;n=m+n|0;n=g+n|0;n=ab(f,n)|0;i=j;return n|0}function ob(a,b){a=a|0;b=b|0;var d=0;d=i;b=c[a+136>>2]|0;b=(ab(b+224|0,b+13|0)|0)==0;i=d;return(b?3:0)|0}function pb(a){a=a|0;var b=0;b=i;a=_a((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function qb(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+17|0)|0;i=b;return a|0}function rb(a){a=a|0;var b=0,d=0,e=0;b=i;e=a+136|0;d=0;while(1){a=d+1|0;if(!(cb((c[e>>2]|0)+224|0)|0)){a=d;d=4;break}if((a|0)<2)d=a;else{d=4;break}}if((d|0)==4){i=b;return a|0}return 0}function sb(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function tb(a){a=a|0;var b=0,d=0;b=i;a=a+136|0;d=c[a>>2]|0;if(!(ab(d+224|0,d+18|0)|0)){d=4;i=b;return d|0}d=(cb((c[a>>2]|0)+224|0)|0)<<1;d=cb((c[a>>2]|0)+224|0)|0|d;i=b;return d|0}function ub(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(42-b)|0)|0;i=d;return a|0}function vb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(b+42)|0)|0;i=d;return a|0}function wb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+((b|0)==0|40)|0)|0;i=d;return a|0}function xb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;a=a+136|0;f=(b<<2)+166|0;e=0;while(1){g=c[a>>2]|0;b=e+1|0;if(!(ab(g+224|0,g+(f+e)|0)|0)){b=e;a=4;break}if((b|0)<4)e=b;else{a=4;break}}if((a|0)==4){i=d;return b|0}return 0}function yb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(b+174)|0)|0;i=d;return a|0}function zb(f,g,h,j,k,l){f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Fa=0,Ga=0,Ia=0,Ja=0,Ka=0,La=0,Na=0;o=i;i=i+96|0;v=o+24|0;u=o+8|0;s=o;t=f+136|0;p=c[t>>2]|0;q=c[f+160>>2]|0;m=c[q+(l<<2)+32>>2]|0;n=f+200|0;T=c[n>>2]|0;h=$(h>>c[T+(l<<2)+13180>>2],m)|0;g=(c[q+(l<<2)>>2]|0)+(h+(g>>c[T+(l<<2)+13168>>2]<>2]))|0;T=(l|0)!=0;h=p+320|0;q=T?p+11680|0:h;w=v+0|0;r=w+64|0;do{a[w>>0]=0;w=w+1|0}while((w|0)<(r|0));S=1<>2]|0;r=S<>0]|0)){A=a[p+272>>0]|0;C=f+204|0;La=c[C>>2]|0;if((a[La+21>>0]|0)!=0?(d[La+1629>>0]|0)>=(j|0):0){F=c[t>>2]|0;F=ab(F+224|0,F+(T&1|46)|0)|0}else F=0;if(y){B=c[n>>2]|0;G=B;B=(c[B+13192>>2]|0)+A|0}else{B=c[C>>2]|0;if((l|0)==1)B=(c[f+2072>>2]|0)+(c[B+28>>2]|0)+(a[p+302>>0]|0)|0;else B=(c[f+2076>>2]|0)+(c[B+32>>2]|0)+(a[p+303>>0]|0)|0;E=B+A|0;G=c[n>>2]|0;A=c[G+13192>>2]|0;B=0-A|0;if((E|0)>=(B|0))B=(E|0)>57?57:E;do if((c[G+4>>2]|0)==1){if((B|0)>=30)if((B|0)>43){B=B+ -6|0;break}else{B=c[176+(B+ -30<<2)>>2]|0;break}}else B=(B|0)>51?51:B;while(0);B=A+B|0}A=(c[G+52>>2]|0)+j|0;E=A+ -5|0;A=1<>0]|0)>>0]<>0];if((a[G+634>>0]|0)!=0?!((F|0)!=0&(j|0)>2):0){H=c[C>>2]|0;H=(a[H+68>>0]|0)==0?G+635|0:H+69|0;G=((c[p+31244>>2]|0)!=1?3:0)+l|0;C=H+((j+ -2|0)*384|0)+(G<<6)|0;if((j|0)>3)ia=a[H+((j+ -4|0)*6|0)+G+1536>>0]|0;else ia=16}else{ia=16;C=0}}else{A=0;ia=0;B=0;C=0;E=0;F=0}J=(j<<1)+ -1|0;if(y){G=(j*3|0)+ -6+(j+ -1>>2)|0;I=j+1>>2}else{G=15;I=j+ -2|0}if((J|0)>0){K=G+52|0;H=0;while(1){La=c[t>>2]|0;L=H+1|0;if(!(ab(La+224|0,La+(K+(H>>I))|0)|0))break;if((L|0)<(J|0))H=L;else{H=L;break}}L=G+70|0;G=0;while(1){La=c[t>>2]|0;K=G+1|0;if(!(ab(La+224|0,La+(L+(G>>I))|0)|0))break;if((K|0)<(J|0))G=K;else{G=K;break}}if((H|0)>3){I=(H>>1)+ -1|0;K=cb((c[t>>2]|0)+224|0)|0;if((I|0)>1){J=1;do{K=cb((c[t>>2]|0)+224|0)|0|K<<1;J=J+1|0}while((J|0)!=(I|0))}H=K+((H&1|2)<3){J=(G>>1)+ -1|0;K=cb((c[t>>2]|0)+224|0)|0;if((J|0)>1){I=1;do{K=cb((c[t>>2]|0)+224|0)|0|K<<1;I=I+1|0}while((I|0)!=(J|0))}I=H;L=K+((G&1|2)<>2;N=L>>2;if((k|0)==1){G=I;H=L;P=d[536+(L<<3)+I>>0]|0;I=488;L=504;J=496;K=520;break}else if(k){J=I;K=L;x=49;break}P=d[(I&3)+(392+((L&3)<<2))>>0]|0;if((S|0)==8){G=I;H=L;P=(d[416+(N<<1)+M>>0]<<4)+P|0;I=496;L=8;J=488;K=24;break}else if((S|0)==16){G=I;H=L;P=(d[392+(N<<2)+M>>0]<<4)+P|0;I=8;L=8;J=24;K=24;break}else if((S|0)==4){G=I;H=L;I=408;L=8;J=408;K=24;break}else{G=I;H=L;P=(d[424+(N<<3)+M>>0]<<4)+P|0;I=40;L=8;J=104;K=24;break}}else{J=L;K=I;M=L>>2;N=I>>2;x=49}while(0);if((x|0)==49){G=J;H=K;P=d[536+(J<<3)+K>>0]|0;I=496;L=520;J=488;K=504}O=P+1|0;Q=P>>4;if((Q|0)>-1){P=(1<0;R=l?90:88;S=S+ -1>>2;W=T?27:0;U=(j|0)==2;T=W+3|0;V=(j|0)==3;Z=(k|0)==0?9:15;_=y?0:27;da=(F|0)==0;aa=y?42:43;fa=y?40:41;ba=y?2:0;ea=p+31244|0;ca=w&-17;ga=f+204|0;Y=((B|0)<0)<<31>>31;X=((A|0)<0)<<31>>31;ha=(F|0)!=0&(j|0)>2;k=(j|0)<4;ia=ia&255;ma=(y&1)<<1;ja=ma|1;ra=1;ka=Q;oa=0;xa=16;while(1){na=ka<<4;wa=a[I+ka>>0]|0;ta=wa&255;va=a[J+ka>>0]|0;ua=va&255;la=(ka|0)>0;if((ka|0)<(Q|0)&la){if((ta|0)<(P|0))pa=d[v+(ta+1<<3)+ua>>0]|0;else pa=0;if((ua|0)<(P|0))pa=(d[ua+1+(v+(ta<<3))>>0]|0)+pa|0;ya=c[t>>2]|0;ya=(ab(ya+224|0,ya+(((pa|0)>1?1:pa)+R)|0)|0)&255;a[v+(ta<<3)+ua>>0]=ya;qa=1}else{if(!((ta|0)==(M|0)&(ua|0)==(N|0)))if(!(wa<<24>>24))ya=va<<24>>24==0&1;else ya=0;else ya=1;a[v+(ta<<3)+ua>>0]=ya;qa=0}na=O-na|0;pa=(ka|0)==(Q|0);if(pa){a[u>>0]=na+255;sa=na+ -2|0;na=1}else{sa=15;na=0}if((ta|0)<(S|0))za=(a[v+(ta+1<<3)+ua>>0]|0)!=0&1;else za=0;if((ua|0)<(S|0))za=((a[ua+1+(v+(ta<<3))>>0]|0)!=0&1)<<1|za;do if(ya<<24>>24!=0&(sa|0)>-1){if(!(c[(c[n>>2]|0)+13100>>2]|0))if(U){wa=600;va=W}else x=73;else if(da){ya=(a[z>>0]|0)!=0;if(ya|U){wa=ya?664:600;va=ya?fa:W}else x=73}else{wa=664;va=fa}do if((x|0)==73){x=0;ya=(za<<4)+616|0;if(!y){wa=ya;va=W+(V?9:12)|0;break}va=(va|wa)<<24>>24==0?W:T;if(V){wa=ya;va=va+Z|0;break}else{wa=ya;va=va+21|0;break}}while(0);if((sa|0)>0){ya=va+92|0;do{La=c[t>>2]|0;if(ab(La+224|0,La+(ya+(d[wa+((d[K+sa>>0]<<2)+(d[L+sa>>0]|0))>>0]|0))|0)|0){a[u+(na&255)>>0]=sa;qa=0;na=na+1<<24>>24}sa=sa+ -1|0}while((sa|0)>0)}if(qa){a[u+(na&255)>>0]=0;qa=na+1<<24>>24;break}if(c[(c[n>>2]|0)+13100>>2]|0)if(da?(a[z>>0]|0)==0:0)x=87;else qa=aa;else x=87;if((x|0)==87){x=0;qa=(ka|0)==0?_:va+2|0}La=c[t>>2]|0;if((ab(La+224|0,La+(qa+92)|0)|0)==1){a[u+(na&255)>>0]=0;qa=na+1<<24>>24}else qa=na}else qa=na;while(0);na=qa&255;a:do if(qa<<24>>24){qa=la?ba:0;if(!(c[(c[n>>2]|0)+13116>>2]|0))Da=0;else{if(da?(a[z>>0]|0)==0:0)oa=ma;else oa=ja;Da=(d[p+oa+199>>0]|0)>>>2}sa=qa|(ra|0)==0&(pa^1)&1;Ba=a[u>>0]|0;va=Ba&255;qa=na>>>0>8?8:na;if(!qa){pa=-1;ra=1}else{ya=sa<<2;pa=-1;ra=1;wa=0;do{La=ra+ya|0;Ka=c[t>>2]|0;La=(ab(Ka+224|0,Ka+((l?La+16|0:La)+136)|0)|0)&255;a[s+wa>>0]=La;if(!(La<<24>>24))ra=((ra+ -1|0)>>>0<2&1)+ra|0;else{pa=(pa|0)==-1?wa:pa;ra=0}wa=wa+1|0}while((wa|0)<(qa|0))}wa=na+ -1|0;qa=a[u+wa>>0]|0;ya=qa&255;do if(!(a[z>>0]|0)){if((c[ea>>2]|0)==1?!((c[(c[n>>2]|0)+13104>>2]|0)==0|da|(ca|0)!=10):0){va=0;break}va=(va-ya|0)>3&1}else va=0;while(0);if((pa|0)!=-1){Ka=c[t>>2]|0;Ka=ab(Ka+224|0,Ka+((l?sa|4:sa)|160)|0)|0;La=s+pa|0;a[La>>0]=(d[La>>0]|0)+Ka}sa=(va|0)==0;if((a[(c[ga>>2]|0)+4>>0]|0)==0|sa){wa=0;va=0;do{va=cb((c[t>>2]|0)+224|0)|0|va<<1;wa=wa+1|0}while((wa|0)<(na|0));za=va<<16-na}else{va=wa&255;if(!((wa&255)<<24>>24))ya=0;else{wa=0;ya=0;do{ya=cb((c[t>>2]|0)+224|0)|0|ya<<1;wa=wa+1|0}while((wa|0)<(va|0))}za=ya<<17-na}ta=ta<<2;va=ua<<2;ua=p+oa+199|0;wa=0;Fa=0;Aa=xa;Ca=0;while(1){xa=Ba&255;ya=(d[L+xa>>0]|0)+ta|0;xa=(d[K+xa>>0]|0)+va|0;b:do if((wa|0)<8){Ga=(d[s+wa>>0]|0)+1|0;La=(wa|0)==(pa|0);if((Ga|0)==((La?3:2)|0)&0==((La?0:0)|0))Ia=0;else{Ia=0;break}while(1){Ja=Ia+1|0;if(!(cb((c[t>>2]|0)+224|0)|0)){x=120;break}if((Ja|0)<31)Ia=Ja;else{x=124;break}}do if((x|0)==120){x=0;if((Ia|0)>=3){Ja=Ia;x=124;break}if((Da|0)>0){Ja=0;Ka=0;do{Ka=cb((c[t>>2]|0)+224|0)|0|Ka<<1;Ja=Ja+1|0}while((Ja|0)!=(Da|0))}else Ka=0;Ja=Ka+(Ia<0){Ka=Da+ -3+Ja|0;Ja=0;La=0;do{La=cb((c[t>>2]|0)+224|0)|0|La<<1;Ja=Ja+1|0}while((Ja|0)!=(Ka|0))}else La=0;Ja=La+((1<>31|0,Ga|0,0)|0;Ia=D;Ka=3<>31;La=c[(c[n>>2]|0)+13116>>2]|0;do if((Ia|0)>(Na|0)|(Ia|0)==(Na|0)&Ga>>>0>Ka>>>0){Ka=Da+1|0;if(La){Da=Ka;break}Da=(Da|0)>3?4:Ka;break b}while(0);if(!((La|0)!=0&(Fa|0)==0))break;Fa=a[ua>>0]|0;Ka=(Fa&255)>>>2;if((Ja|0)>=(3<>0]=Fa+1<<24>>24;Fa=1;break}if((Ja<<1|0)>=(1<>24==0){Fa=1;break}a[ua>>0]=Fa+ -1<<24>>24;Fa=1}else{Ga=0;while(1){Ia=Ga+1|0;if(!(cb((c[t>>2]|0)+224|0)|0)){x=138;break}if((Ia|0)<31)Ga=Ia;else{x=142;break}}do if((x|0)==138){x=0;if((Ga|0)>=3){Ia=Ga;x=142;break}if((Da|0)>0){Ia=0;Ja=0;do{Ja=cb((c[t>>2]|0)+224|0)|0|Ja<<1;Ia=Ia+1|0}while((Ia|0)!=(Da|0))}else Ja=0;Ja=Ja+(Ga<0){Ja=Da+ -3+Ia|0;Ia=0;Ka=0;do{Ka=cb((c[t>>2]|0)+224|0)|0|Ka<<1;Ia=Ia+1|0}while((Ia|0)!=(Ja|0))}else Ka=0;Ja=Ka+((1<>31;La=c[(c[n>>2]|0)+13116>>2]|0;do if((Ja|0)>=(3<3?4:Ka;break b}while(0);if(!((La|0)!=0&(Fa|0)==0))break;Ka=a[ua>>0]|0;Fa=(Ka&255)>>>2;if((Ja|0)>=(3<>0]=Ka+1<<24>>24;Fa=1;break}if((Ja<<1|0)>=(1<>24==0){Fa=1;break}a[ua>>0]=Ka+ -1<<24>>24;Fa=1}while(0);do if(!((a[(c[ga>>2]|0)+4>>0]|0)==0|sa)){Ca=_d(Ga|0,Ia|0,Ca|0,0)|0;if(Ba<<24>>24!=qa<<24>>24)break;Na=(Ca&1|0)==0;La=Zd(0,0,Ga|0,Ia|0)|0;Ga=Na?Ga:La;Ia=Na?Ia:D}while(0);Na=(za&32768|0)==0;Ba=Zd(0,0,Ga|0,Ia|0)|0;Ba=Na?Ga:Ba;Ga=Na?Ia:D;za=za<<1&131070;Ia=Ba&65535;do if(!(a[z>>0]|0)){do if(!((a[(c[n>>2]|0)+634>>0]|0)==0|ha)){if(!((xa|ya|0)!=0|k)){Aa=ia;break}if((j|0)==3)Aa=(xa<<3)+ya|0;else if((j|0)==4)Aa=(xa>>>1<<3)+(ya>>>1)|0;else if((j|0)==5)Aa=(xa>>>2<<3)+(ya>>>2)|0;else Aa=(xa<<2)+ya|0;Aa=d[C+Aa>>0]|0}while(0);Ba=he(Ba|0,Ga|0,B|0,Y|0)|0;Ba=he(Ba|0,D|0,Aa|0,((Aa|0)<0)<<31>>31|0)|0;Ba=_d(Ba|0,D|0,A|0,X|0)|0;Ba=Yd(Ba|0,D|0,E|0)|0;Ga=D;if((Ga|0)<0){Ia=(Ba&-32768|0)==-32768&(Ga&268435455|0)==268435455?Ba&65535:-32768;break}else{Ia=Ga>>>0>0|(Ga|0)==0&Ba>>>0>32767?32767:Ba&65535;break}}while(0);b[q+((xa<>1]=Ia;wa=wa+1|0;if((wa|0)>=(na|0)){xa=Aa;break a}Ba=a[u+wa>>0]|0}}while(0);if(la)ka=ka+ -1|0;else break}}do if(a[z>>0]|0){if((c[(c[n>>2]|0)+13104>>2]|0)!=0?(w&-17|0)==10:0)Ha[c[f+2632>>2]&7](q,j&65535,(w|0)==26&1)}else{if(F){s=c[n>>2]|0;if((c[s+13096>>2]|0)!=0&(j|0)==2?(c[p+31244>>2]|0)==1:0){t=0;do{Ka=q+(15-t<<1)|0;La=b[Ka>>1]|0;Na=q+(t<<1)|0;b[Ka>>1]=b[Na>>1]|0;b[Na>>1]=La;t=t+1|0}while((t|0)!=8)}t=j&65535;Ha[c[f+2628>>2]&7](q,t,c[s+52>>2]|0);if(!(c[(c[n>>2]|0)+13104>>2]|0))break;if((c[p+31244>>2]|0)!=1)break;if((w&-17|0)!=10)break;Ha[c[f+2632>>2]&7](q,t,(w|0)==26&1);break}if(y&(c[p+31244>>2]|0)==1&(j|0)==2){Ea[c[f+2636>>2]&7](q,c[(c[n>>2]|0)+52>>2]|0);break}s=(G|0)>(H|0)?G:H;if(!s){Ea[c[f+(j+ -2<<2)+2656>>2]&7](q,c[(c[n>>2]|0)+52>>2]|0);break}t=H+4+G|0;do if((s|0)>=4){if((s|0)<8){t=(t|0)<8?t:8;break}if((s|0)<12)t=(t|0)<24?t:24}else t=(t|0)<4?t:4;while(0);Ha[c[f+(j+ -2<<2)+2640>>2]&7](q,t,c[(c[n>>2]|0)+52>>2]|0)}while(0);if(!(a[p+304>>0]|0)){La=j+ -2|0;La=f+(La<<2)+2612|0;La=c[La>>2]|0;Na=c[n>>2]|0;Na=Na+52|0;Na=c[Na>>2]|0;Ma[La&7](g,q,m,Na);i=o;return}if((r|0)<=0){La=j+ -2|0;La=f+(La<<2)+2612|0;La=c[La>>2]|0;Na=c[n>>2]|0;Na=Na+52|0;Na=c[Na>>2]|0;Ma[La&7](g,q,m,Na);i=o;return}p=c[p+284>>2]|0;s=0;do{Na=q+(s<<1)|0;b[Na>>1]=(($(b[h+(s<<1)>>1]|0,p)|0)>>>3)+(e[Na>>1]|0);s=s+1|0}while((s|0)!=(r|0));La=j+ -2|0;La=f+(La<<2)+2612|0;La=c[La>>2]|0;Na=c[n>>2]|0;Na=Na+52|0;Na=c[Na>>2]|0;Ma[La&7](g,q,m,Na);i=o;return}function Ab(a){a=a|0;var b=0,e=0,f=0;b=i;f=a+16|0;e=c[f>>2]|0;c[a>>2]=(c[a>>2]|0)+ -65535+((d[e+1>>0]|0)<<1|(d[e>>0]|0)<<9);if(e>>>0>=(c[a+20>>2]|0)>>>0){i=b;return}c[f>>2]=e+2;i=b;return}function Bb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;f=i;h=b+136|0;n=c[h>>2]|0;g=b+200|0;j=c[g>>2]|0;m=c[j+13080>>2]|0;q=(1<>2]|0)+24>>2]|0);o=m&d;p=m&e;k=c[j+13140>>2]|0;j=c[j+13064>>2]|0;l=o>>j;j=p>>j;if(!(q&d))o=0;else o=(o&q|0)!=0;if(!(q&e))p=0;else p=(p&q|0)!=0;q=n+203|0;if((a[q>>0]|0)==0?(m&(e|d)|0)!=0:0)d=c[n+276>>2]|0;else{a[q>>0]=(a[n+300>>0]|0)==0&1;d=a[b+2112>>0]|0}if(o){e=l+ -1+($(j,k)|0)|0;e=a[(c[b+4316>>2]|0)+e>>0]|0}else e=d;if(p){d=($(j+ -1|0,k)|0)+l|0;d=a[(c[b+4316>>2]|0)+d>>0]|0}b=e+1+d>>1;h=c[h>>2]|0;j=c[h+280>>2]|0;if(!j){a[h+272>>0]=b;i=f;return}g=c[(c[g>>2]|0)+13192>>2]|0;b=j+52+b+(g<<1)|0;if((b|0)>0)j=b;else j=-52-g+1+b|0;a[h+272>>0]=b-g-j+((j|0)%(g+52|0)|0);i=f;return}function Cb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;g=i;j=c[b+136>>2]|0;k=b+200|0;do if((e|0)>0&(e&7|0)==0){if(((a[b+2062>>0]|0)==0?(c[j+31312>>2]&4|0)!=0:0)?((e|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0)break;if(((a[(c[b+204>>2]|0)+53>>0]|0)==0?(c[j+31312>>2]&8|0)!=0:0)?((e|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0)break;h=1<0){l=b+2596|0;m=b+4320|0;n=0;do{o=n+d+($(c[l>>2]|0,e)|0)>>2;a[(c[m>>2]|0)+o>>0]=2;n=n+4|0}while((n|0)<(h|0))}}while(0);if(!((d|0)>0&(d&7|0)==0)){i=g;return}if(((a[b+2062>>0]|0)==0?(c[j+31312>>2]&1|0)!=0:0)?((d|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0){i=g;return}if(((a[(c[b+204>>2]|0)+53>>0]|0)==0?(c[j+31312>>2]&2|0)!=0:0)?((d|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0){i=g;return}h=1<>2]|0,k+e|0)|0)+d>>2;a[(c[b>>2]|0)+o>>0]=2;k=k+4|0}while((k|0)<(h|0));i=g;return}function Db(e,f,g,h){e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0;j=i;i=i+32|0;o=j+8|0;x=j;n=j+18|0;s=j+16|0;l=e+200|0;K=c[l>>2]|0;v=c[K+13120>>2]|0;k=(v-h|0)<=(f|0);b[n>>1]=0;b[s>>1]=0;w=c[K+13080>>2]|0;u=1<>w,c[K+13128>>2]|0)|0)+(f>>w)|0;t=c[e+2508>>2]|0;m=c[t+(w<<3)+4>>2]|0;y=c[t+(w<<3)>>2]|0;if((c[K+68>>2]|0)!=0?(a[K+13056>>0]|0)!=0:0)p=1;else p=(a[(c[e+204>>2]|0)+40>>0]|0)!=0;r=c[K+52>>2]|0;q=(f|0)!=0;if(q){w=w+ -1|0;z=c[t+(w<<3)>>2]|0;w=c[t+(w<<3)+4>>2]|0}else{z=0;w=0}t=u+f|0;t=(t|0)>(v|0)?v:t;u=u+g|0;A=c[K+13124>>2]|0;u=(u|0)>(A|0)?A:u;A=(t|0)==(v|0)?t:t+ -8|0;v=(u|0)>(g|0);if(v){K=q?f:8;N=(K|0)<(t|0);Q=q?f+ -8|0:0;F=e+2596|0;P=e+4320|0;I=e+4316|0;C=x+4|0;D=e+160|0;E=n+1|0;R=s+1|0;L=e+4300|0;M=e+4284|0;J=e+4324|0;G=e+4304|0;H=e+4288|0;B=(Q|0)>=(A|0);U=y;T=m;O=g;do{if(N){W=O+4|0;X=T+ -2&-2;V=K;do{_=c[F>>2]|0;da=($(_,O)|0)+V>>2;aa=c[J>>2]|0;da=a[aa+da>>0]|0;ca=da&255;_=a[aa+(($(_,W)|0)+V>>2)>>0]|0;aa=_&255;da=da<<24>>24!=0;_=_<<24>>24==0;do if(!(_&(da^1))){S=V+ -1|0;Y=c[l>>2]|0;ba=c[Y+13064>>2]|0;Z=$(O>>ba,c[Y+13140>>2]|0)|0;ea=c[I>>2]|0;ba=(a[ea+(Z+(S>>ba))>>0]|0)+1+(a[ea+(Z+(V>>ba))>>0]|0)>>1;Z=ba+U|0;if((Z|0)<0)Z=0;else Z=(Z|0)>51?51:Z;Z=d[1280+Z>>0]|0;if(da){ca=(ca<<1)+X+ba|0;if((ca|0)<0)ca=0;else ca=(ca|0)>53?53:ca;ca=d[1336+ca>>0]|0}else ca=0;c[x>>2]=ca;if(_)_=0;else{_=(aa<<1)+X+ba|0;if((_|0)<0)_=0;else _=(_|0)>53?53:_;_=d[1336+_>>0]|0}c[C>>2]=_;da=c[D>>2]|0;_=c[da+32>>2]|0;ea=$(_,O)|0;Y=(c[da>>2]|0)+((V<>2])+ea)|0;if(p){a[n>>0]=Ib(e,S,O)|0;a[E>>0]=Ib(e,S,W)|0;a[s>>0]=Ib(e,V,O)|0;a[R>>0]=Ib(e,V,W)|0;Ba[c[G>>2]&7](Y,_,Z,x,n,s,r);break}else{Ba[c[H>>2]&7](Y,_,Z,x,n,s,r);break}}while(0);V=V+8|0}while((V|0)<(t|0))}if(!((O|0)==0|B)){S=O+ -1|0;W=T;T=Q;do{Z=$(c[F>>2]|0,O)|0;_=c[P>>2]|0;ba=a[_+(Z+T>>2)>>0]|0;ca=ba&255;V=T+4|0;Z=a[_+(Z+V>>2)>>0]|0;_=Z&255;ba=ba<<24>>24!=0;Z=Z<<24>>24==0;do if(!(Z&(ba^1))){X=c[l>>2]|0;W=c[X+13064>>2]|0;aa=T>>W;U=c[X+13140>>2]|0;ea=($(S>>W,U)|0)+aa|0;Y=c[I>>2]|0;aa=(a[Y+ea>>0]|0)+1+(a[Y+(($(O>>W,U)|0)+aa)>>0]|0)>>1;U=(T|0)>=(f|0);W=U?m:w;U=U?y:z;Y=aa+U|0;if((Y|0)<0)Y=0;else Y=(Y|0)>51?51:Y;Y=d[1280+Y>>0]|0;if(ba){ba=(ca<<1)+(W+ -2&-2)+aa|0;if((ba|0)<0)ba=0;else ba=(ba|0)>53?53:ba;ba=d[1336+ba>>0]|0}else ba=0;c[x>>2]=ba;if(Z)Z=0;else{Z=(_<<1)+(W+ -2&-2)+aa|0;if((Z|0)<0)Z=0;else Z=(Z|0)>53?53:Z;Z=d[1336+Z>>0]|0}c[C>>2]=Z;da=c[D>>2]|0;Z=c[da+32>>2]|0;ea=$(Z,O)|0;X=(c[da>>2]|0)+((T<>2])+ea)|0;if(p){a[n>>0]=Ib(e,T,S)|0;a[E>>0]=Ib(e,V,S)|0;a[s>>0]=Ib(e,T,O)|0;a[R>>0]=Ib(e,V,O)|0;Ba[c[L>>2]&7](X,Z,Y,x,n,s,r);break}else{Ba[c[M>>2]&7](X,Z,Y,x,n,s,r);break}}while(0);T=T+8|0}while((T|0)<(A|0));T=W}O=O+8|0}while((O|0)<(u|0));K=c[l>>2]|0}else T=m;if(c[K+4>>2]|0){D=q?w:m;G=e+2596|0;F=e+4320|0;w=e+4316|0;y=o+4|0;x=e+160|0;C=n+1|0;B=s+1|0;E=e+4308|0;H=e+4292|0;I=e+4324|0;A=e+4312|0;z=e+4296|0;J=1;do{P=1<>2];Q=1<>2];if(v){O=P<<3;M=q?f:O;L=(M|0)<(t|0);K=Q<<3;N=q?f-O|0:0;P=P<<2;Q=Q<<2;R=g;do{if(L){S=R+Q|0;U=M;do{X=c[G>>2]|0;Z=($(X,R)|0)+U>>2;ea=c[I>>2]|0;Z=(a[ea+Z>>0]|0)==2;X=(a[ea+(($(X,S)|0)+U>>2)>>0]|0)==2;do if(Z|X){V=U+ -1|0;W=c[l>>2]|0;ea=c[W+13064>>2]|0;_=V>>ea;Y=c[W+13140>>2]|0;ba=$(R>>ea,Y)|0;aa=c[w>>2]|0;ca=U>>ea;Y=$(S>>ea,Y)|0;Y=(a[aa+(Y+_)>>0]|0)+1+(a[aa+(Y+ca)>>0]|0)>>1;if(Z)Z=Jb(e,(a[aa+(ba+ca)>>0]|0)+1+(a[aa+(ba+_)>>0]|0)>>1,J,T)|0;else Z=0;c[o>>2]=Z;if(X)X=Jb(e,Y,J,T)|0;else X=0;c[y>>2]=X;da=c[x>>2]|0;X=c[da+(J<<2)+32>>2]|0;ea=$(X,R>>c[W+(J<<2)+13180>>2])|0;W=(c[da+(J<<2)>>2]|0)+((U>>c[W+(J<<2)+13168>>2]<>2])+ea)|0;if(p){a[n>>0]=Ib(e,V,R)|0;a[C>>0]=Ib(e,V,S)|0;a[s>>0]=Ib(e,U,R)|0;a[B>>0]=Ib(e,U,S)|0;Ja[c[A>>2]&3](W,X,o,n,s,r);break}else{Ja[c[z>>2]&3](W,X,o,n,s,r);break}}while(0);U=U+O|0}while((U|0)<(t|0))}if(R){V=t-((t|0)==(c[(c[l>>2]|0)+13120>>2]|0)?0:O)|0;if((N|0)<(V|0)){U=R+ -1|0;T=N;do{X=$(c[G>>2]|0,R)|0;ea=c[F>>2]|0;S=T+P|0;Y=(a[ea+(X+T>>2)>>0]|0)==2;X=(a[ea+(X+S>>2)>>0]|0)==2;do if(Y|X){if(Y){ea=c[l>>2]|0;da=c[ea+13064>>2]|0;Z=T>>da;ea=c[ea+13140>>2]|0;ba=($(U>>da,ea)|0)+Z|0;ca=c[w>>2]|0;Z=(a[ca+ba>>0]|0)+1+(a[ca+(($(R>>da,ea)|0)+Z)>>0]|0)>>1}else Z=0;if(X){ea=c[l>>2]|0;da=c[ea+13064>>2]|0;W=S>>da;ea=c[ea+13140>>2]|0;ba=($(U>>da,ea)|0)+W|0;ca=c[w>>2]|0;W=(a[ca+ba>>0]|0)+1+(a[ca+(($(R>>da,ea)|0)+W)>>0]|0)>>1}else W=0;if(Y)Y=Jb(e,Z,J,D)|0;else Y=0;c[o>>2]=Y;if(X)W=Jb(e,W,J,m)|0;else W=0;c[y>>2]=W;ea=c[l>>2]|0;da=c[x>>2]|0;X=c[da+(J<<2)+32>>2]|0;W=$(X,R>>c[ea+13184>>2])|0;W=(c[da+(J<<2)>>2]|0)+((T>>c[ea+13172>>2]<>2])+W)|0;if(p){a[n>>0]=Ib(e,T,U)|0;a[C>>0]=Ib(e,S,U)|0;a[s>>0]=Ib(e,T,R)|0;a[B>>0]=Ib(e,S,R)|0;Ja[c[E>>2]&3](W,X,o,n,s,r);break}else{Ja[c[H>>2]&3](W,X,o,n,s,r);break}}while(0);T=T+O|0}while((T|0)<(V|0));T=D}else T=D}R=R+K|0}while((R|0)<(u|0))}J=J+1|0;K=c[l>>2]|0}while((J|0)!=3)}if(!(a[K+12941>>0]|0)){if((a[e+140>>0]&1)==0|k^1){i=j;return}i=j;return}n=(c[K+13124>>2]|0)-h|0;l=(g|0)==0;m=(f|0)==0;if(!(l|m))Eb(e,f-h|0,g-h|0);n=(n|0)>(g|0);if(!(m|n))Eb(e,f-h|0,g);k=k^1;!(l|k)?(Eb(e,f,g-h|0),(a[e+140>>0]&1)!=0):0;if(n|k){i=j;return}Eb(e,f,g);if(!(a[e+140>>0]&1)){i=j;return}i=j;return}function Eb(e,f,g){e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0;h=i;i=i+48|0;l=h+24|0;r=h+42|0;s=h+40|0;p=h+16|0;k=h+8|0;t=h;o=e+200|0;S=c[o>>2]|0;y=c[S+13080>>2]|0;j=f>>y;y=g>>y;G=S+13128|0;n=($(y,c[G>>2]|0)|0)+j|0;M=c[e+204>>2]|0;L=M+1668|0;N=c[(c[L>>2]|0)+(n<<2)>>2]|0;A=e+2504|0;m=c[A>>2]|0;q=m+(n*148|0)|0;b[r>>1]=0;b[s>>1]=0;c[p>>2]=0;F=($(c[G>>2]|0,y)|0)+j|0;F=a[(c[e+4352>>2]|0)+F>>0]|0;if((a[M+42>>0]|0)!=0?(a[M+53>>0]|0)==0:0){R=1;O=1}else{R=F<<24>>24==0&1;O=0}D=(j|0)==0;c[l>>2]=D&1;I=(y|0)==0;u=l+4|0;c[u>>2]=I&1;H=(j|0)==((c[G>>2]|0)+ -1|0);z=l+8|0;c[z>>2]=H&1;E=(y|0)==((c[S+13132>>2]|0)+ -1|0);x=l+12|0;c[x>>2]=E&1;if(R<<24>>24){if(D)J=0;else{if(O){J=c[M+1676>>2]|0;J=(c[J+(N<<2)>>2]|0)!=(c[J+(c[(c[L>>2]|0)+(n+ -1<<2)>>2]<<2)>>2]|0)&1}else J=0;if(F<<24>>24==0?(pa=$(c[G>>2]|0,y)|0,oa=c[e+4328>>2]|0,(c[oa+(pa+j<<2)>>2]|0)!=(c[oa+(j+ -1+pa<<2)>>2]|0)):0)K=1;else K=J;a[r>>0]=K}if(H)K=0;else{if(O){K=c[M+1676>>2]|0;K=(c[K+(N<<2)>>2]|0)!=(c[K+(c[(c[L>>2]|0)+(n+1<<2)>>2]<<2)>>2]|0)&1}else K=0;if(F<<24>>24==0?(pa=$(c[G>>2]|0,y)|0,oa=c[e+4328>>2]|0,(c[oa+(pa+j<<2)>>2]|0)!=(c[oa+(j+1+pa<<2)>>2]|0)):0)P=1;else P=K;a[r+1>>0]=P}if(I)P=0;else{if(O){P=c[M+1676>>2]|0;P=(c[P+(N<<2)>>2]|0)!=(c[P+(c[(c[L>>2]|0)+(n-(c[G>>2]|0)<<2)>>2]<<2)>>2]|0)&1}else P=0;if(F<<24>>24==0?(pa=c[G>>2]|0,na=($(pa,y)|0)+j|0,oa=c[e+4328>>2]|0,(c[oa+(na<<2)>>2]|0)!=(c[oa+(($(pa,y+ -1|0)|0)+j<<2)>>2]|0)):0)Q=1;else Q=P;a[s>>0]=Q}if(E)L=0;else{if(O){pa=c[M+1676>>2]|0;L=(c[pa+(N<<2)>>2]|0)!=(c[pa+(c[(c[L>>2]|0)+((c[G>>2]|0)+n<<2)>>2]<<2)>>2]|0)&1}else L=0;if(F<<24>>24==0?(pa=c[G>>2]|0,na=($(pa,y)|0)+j|0,oa=c[e+4328>>2]|0,(c[oa+(na<<2)>>2]|0)!=(c[oa+(($(pa,y+1|0)|0)+j<<2)>>2]|0)):0)M=1;else M=L;a[s+1>>0]=M}if(!D)if(I)B=47;else{if(!(F<<24>>24)){pa=c[G>>2]|0;na=($(pa,y)|0)+j|0;oa=c[e+4328>>2]|0;if(J<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(j+ -1+($(pa,y+ -1|0)|0)<<2)>>2]|0):0)B=38;else M=1}else if(!(J<<24>>24))B=38;else M=1;if((B|0)==38)M=P<<24>>24!=0&1;a[p>>0]=M;B=40}else B=40;if((B|0)==40)if(!I){if(!H){if(!(F<<24>>24)){pa=c[G>>2]|0;na=($(pa,y)|0)+j|0;oa=c[e+4328>>2]|0;if(K<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(j+1+($(pa,y+ -1|0)|0)<<2)>>2]|0):0)B=45;else I=1}else if(!(K<<24>>24))B=45;else I=1;if((B|0)==45)I=P<<24>>24!=0&1;a[p+1>>0]=I;B=47}}else B=47;if((B|0)==47?!(H|E):0){if(!(F<<24>>24)){pa=c[G>>2]|0;na=($(pa,y)|0)+j|0;oa=c[e+4328>>2]|0;if(K<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(j+1+($(pa,y+1|0)|0)<<2)>>2]|0):0)B=51;else H=1}else if(!(K<<24>>24))B=51;else H=1;if((B|0)==51)H=L<<24>>24!=0&1;a[p+2>>0]=H}if(!(D|E)){if(!(F<<24>>24)){pa=c[G>>2]|0;na=($(pa,y)|0)+j|0;oa=c[e+4328>>2]|0;if(J<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(j+ -1+($(pa,y+1|0)|0)<<2)>>2]|0):0)B=57;else D=1}else if(!(J<<24>>24))B=57;else D=1;if((B|0)==57)D=L<<24>>24!=0&1;a[p+3>>0]=D}}N=(c[S+4>>2]|0)!=0?3:1;E=e+160|0;D=e+168|0;F=e+2672|0;P=y<<1;H=P+ -1|0;G=k+4|0;O=y+ -1|0;J=j+1|0;L=j+ -1|0;P=P+2|0;Q=t+4|0;M=y+1|0;I=j<<1;K=I+ -1|0;I=I+2|0;R=e+((R&255)<<2)+2676|0;na=S;_=0;while(1){ka=c[na+(_<<2)+13168>>2]|0;V=f>>ka;ha=c[na+(_<<2)+13180>>2]|0;aa=g>>ha;ba=c[E>>2]|0;W=c[ba+(_<<2)+32>>2]|0;S=1<>2];Z=S>>ka;Y=S>>ha;ka=c[na+13120>>2]>>ka;ca=ka-V|0;Z=(Z|0)>(ca|0)?ca:Z;ha=c[na+13124>>2]>>ha;ca=ha-aa|0;Y=(Y|0)>(ca|0)?ca:Y;ca=$(W,aa)|0;fa=c[na+56>>2]|0;ca=(V<>2]|0;X=ba+ca|0;S=S+2<>2]|0;ga=1<>0]|0;if((ia|0)==2){ja=c[l>>2]|0;ia=c[z>>2]|0;la=c[x>>2]|0;do if(!(c[u>>2]|0)){pa=1-ja|0;oa=pa<>2]=ba+(ca-W-oa);c[G>>2]=(c[e+(_<<2)+172>>2]|0)+(($(ka,H)|0)+V-pa<>2]|0,O)|0)|0;pa=c[k+(((a[(c[A>>2]|0)+(pa*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0;if(!fa){a[oa>>0]=a[pa>>0]|0;na=c[o>>2]|0;oa=ga;break}else{b[oa>>1]=b[pa>>1]|0;oa=ga;break}}else oa=0;while(0);pa=($(c[na+13128>>2]|0,O)|0)+j|0;na=Z<>2]|0)+(pa*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0)+oa|0,na|0)|0;if((ia|0)!=1){pa=oa+na|0;oa=J+($(c[(c[o>>2]|0)+13128>>2]|0,O)|0)|0;na=ea+(pa+ma)|0;ma=(c[k+(((a[(c[A>>2]|0)+(oa*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0)+pa|0;if(!fa){a[na>>0]=a[ma>>0]|0;break}else{b[na>>1]=b[ma>>1]|0;break}}}while(0);do if(!la){pa=1-ja|0;oa=pa<>2]=ba+(($(Y,W)|0)+ca-oa);c[Q>>2]=(c[e+(_<<2)+172>>2]|0)+(($(ka,P)|0)+V-pa<>2]|0)+13128>>2]|0,M)|0)|0;ma=c[t+(((a[(c[A>>2]|0)+(ma*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0;if(!fa){a[ka>>0]=a[ma>>0]|0;ma=ga;break}else{b[ka>>1]=b[ma>>1]|0;ma=ga;break}}else ma=0;while(0);pa=($(c[(c[o>>2]|0)+13128>>2]|0,M)|0)+j|0;ka=Z<>2]|0)+(pa*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0)+ma|0,ka|0)|0;if((ia|0)!=1){pa=ma+ka|0;oa=J+($(c[(c[o>>2]|0)+13128>>2]|0,M)|0)|0;ka=ea+(pa+la)|0;la=(c[t+(((a[(c[A>>2]|0)+(oa*148|0)+_+142>>0]|0)==3&1)<<2)>>2]|0)+pa|0;if(!fa){a[ka>>0]=a[la>>0]|0;break}else{b[ka>>1]=b[la>>1]|0;break}}}while(0);do if(!ja){pa=L+($(c[(c[o>>2]|0)+13128>>2]|0,y)|0)|0;if((a[(c[A>>2]|0)+(pa*148|0)+_+142>>0]|0)==3){la=ea+S|0;ja=(c[e+(_<<2)+184>>2]|0)+(($(ha,K)|0)+aa<0;if(!fa){if(ka)ka=0;else{ja=0;break}while(1){a[la>>0]=a[ja>>0]|0;ka=ka+1|0;if((ka|0)==(Y|0)){ja=0;break}else{la=la+S|0;ja=ja+ga|0}}}else{if(ka)ka=0;else{ja=0;break}while(1){b[la>>1]=b[ja>>1]|0;ka=ka+1|0;if((ka|0)==(Y|0)){ja=0;break}else{la=la+S|0;ja=ja+ga|0}}}}else ja=1}else ja=0;while(0);do if(!ia){pa=J+($(c[(c[o>>2]|0)+13128>>2]|0,y)|0)|0;if((a[(c[A>>2]|0)+(pa*148|0)+_+142>>0]|0)==3){ia=ea+((Z<>2]|0)+(($(ha,I)|0)+aa<0;if(!fa){if(ka)B=0;else break;while(1){a[ia>>0]=a[ha>>0]|0;B=B+1|0;if((B|0)==(Y|0)){C=0;B=96;break}else{ia=ia+S|0;ha=ha+ga|0}}}else{if(ka)B=0;else break;while(1){b[ia>>1]=b[ha>>1]|0;B=B+1|0;if((B|0)==(Y|0)){C=0;B=96;break}else{ia=ia+S|0;ha=ha+ga|0}}}}else{C=1;B=96}}else{C=0;B=96}while(0);if((B|0)==96?(B=0,v=ja<0):0){da=ea+(da-v)|0;ea=0;ba=ba+(ca-v)|0;while(1){ce(da|0,ba|0,w|0)|0;ea=ea+1|0;if((ea|0)==(Y|0))break;else{da=da+S|0;ba=ba+W|0}}}Gb(e,X,W,V,aa,Z,Y,_,j,y);Ca[c[R>>2]&3](X,U,W,S,q,l,Z,Y,_,r,s,p,c[(c[o>>2]|0)+52>>2]|0);Hb(e,X,U,W,S,f,g,Z,Y,_);a[T>>0]=3}else if((ia|0)==1){ca=Z<0){ba=U;da=0;ea=X;while(1){ce(ba|0,ea|0,ca|0)|0;da=da+1|0;if((da|0)==(Y|0))break;else{ba=ba+S|0;ea=ea+W|0}}}Gb(e,X,W,V,aa,Z,Y,_,j,y);Aa[c[F>>2]&1](X,U,W,S,q,l,Z,Y,_,c[(c[o>>2]|0)+52>>2]|0);Hb(e,X,U,W,S,f,g,Z,Y,_);a[T>>0]=3}_=_+1|0;if((_|0)>=(N|0))break;na=c[o>>2]|0}i=h;return}function Fb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;h=c[a+200>>2]|0;k=((c[h+13120>>2]|0)-e|0)>(b|0);h=((c[h+13124>>2]|0)-e|0)>(d|0);j=(d|0)==0;g=(b|0)==0;if(!(j|g))Db(a,b-e|0,d-e|0,e);if(!(j|k))Db(a,b,d-e|0,e);if(g|h){i=f;return}Db(a,b-e|0,d,e);i=f;return}function Gb(d,e,f,g,h,j,k,l,m,n){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0;o=i;q=c[d+200>>2]|0;p=c[q+56>>2]|0;s=c[q+13120>>2]>>c[q+(l<<2)+13168>>2];q=c[q+13124>>2]>>c[q+(l<<2)+13180>>2];u=d+(l<<2)+172|0;t=n<<1;r=j<>2]|0)+(($(s,t)|0)+g<>2]|0)+(($(s,t|1)|0)+g<>2]|0;l=m<<1;t=r+(($(q,l)|0)+h<0;if(n){if(g){r=t;t=0;s=e;while(1){a[r>>0]=a[s>>0]|0;t=t+1|0;if((t|0)==(k|0))break;else{r=r+m|0;s=s+f|0}}r=c[d>>2]|0}}else if(g){d=0;s=e;while(1){b[t>>1]=b[s>>1]|0;d=d+1|0;if((d|0)==(k|0))break;else{t=t+m|0;s=s+f|0}}}h=r+(($(q,l|1)|0)+h<>0]=a[j>>0]|0;p=p+1|0;if((p|0)==(k|0))break;else{h=h+m|0;j=j+f|0}}i=o;return}else{if(g)p=0;else{i=o;return}while(1){b[h>>1]=b[j>>1]|0;p=p+1|0;if((p|0)==(k|0))break;else{h=h+m|0;j=j+f|0}}i=o;return}}function Hb(b,d,e,f,g,h,j,k,l,m){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;n=i;t=c[b+200>>2]|0;if(!(a[(c[b+204>>2]|0)+40>>0]|0)){if(!(a[t+13056>>0]|0)){i=n;return}if(!(c[t+68>>2]|0)){i=n;return}}p=b+200|0;C=c[t+13084>>2]|0;v=1<>2]|0;s=c[t+(m<<2)+13180>>2]|0;m=h>>C;z=j>>C;k=k+h>>C;l=l+j>>C;t=v>>o<>2];if((z|0)>=(l|0)){i=n;return}u=(m|0)<(k|0);b=b+4348|0;v=v>>s;w=(v|0)>0;do{if(u){x=z-j|0;y=m;do{A=c[p>>2]|0;C=($(c[A+13156>>2]|0,z)|0)+y|0;if((a[(c[b>>2]|0)+C>>0]|0)!=0?(r=c[A+13084>>2]|0,q=x<>s,r=y-h<>o<>2],w):0){C=e+(($(q,g)|0)+r)|0;A=0;B=d+(($(q,f)|0)+r)|0;while(1){ce(B|0,C|0,t|0)|0;A=A+1|0;if((A|0)==(v|0))break;else{C=C+g|0;B=B+f|0}}}y=y+1|0}while((y|0)!=(k|0))}z=z+1|0}while((z|0)!=(l|0));i=n;return}function Ib(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0;f=i;g=c[a+200>>2]|0;h=c[g+13084>>2]|0;if((e|b|0)<0){e=2;i=f;return e|0}b=b>>h;e=e>>h;h=c[g+13156>>2]|0;if((b|0)>=(h|0)){e=2;i=f;return e|0}if((e|0)>=(c[g+13160>>2]|0)){e=2;i=f;return e|0}e=($(h,e)|0)+b|0;e=d[(c[a+4348>>2]|0)+e>>0]|0;i=f;return e|0}function Jb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0;h=i;j=c[b+204>>2]|0;e=(c[((f|0)==1?j+28|0:j+32|0)>>2]|0)+e|0;if((e|0)<0)e=0;else e=(e|0)>57?57:e;do if((c[(c[b+200>>2]|0)+4>>2]|0)==1){if((e|0)>=30)if((e|0)>43){e=e+ -6|0;break}else{e=d[1392+(e+ -30)>>0]|0;break}}else if((e|0)<0)e=0;else e=(e|0)>51?51:e;while(0);g=g+2+e|0;if((g|0)<0){j=0;j=1336+j|0;j=a[j>>0]|0;j=j&255;i=h;return j|0}j=(g|0)>53?53:g;j=1336+j|0;j=a[j>>0]|0;j=j&255;i=h;return j|0}function Kb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;k=b+4376|0;c[k>>2]=0;a:do if((e|0)>1){m=0;while(1){if(!(a[d+m>>0]|0)){if((m|0)>0){l=m+ -1|0;l=(a[d+l>>0]|0)==0?l:m}else l=m;m=l+2|0;if(((m|0)<(e|0)?(a[d+(l+1)>>0]|0)==0:0)?(j=a[d+m>>0]|0,(j&255)<4):0)break}else l=m;m=l+2|0;if((l+3|0)>=(e|0))break a}m=l;e=j<<24>>24==3?e:l}else m=0;while(0);if((m|0)>=(e+ -1|0)){c[f+12>>2]=d;c[f+8>>2]=e;q=e;i=g;return q|0}od(f,f+4|0,e+32|0);j=c[f>>2]|0;if(!j){q=-12;i=g;return q|0}ce(j|0,d|0,m|0)|0;o=m+2|0;b:do if((o|0)<(e|0)){l=b+4384|0;b=b+4380|0;n=m;c:while(1){p=d+o|0;q=a[p>>0]|0;do if((q&255)<=3){p=a[d+m>>0]|0;if(!(p<<24>>24))if(!(a[d+(m+1)>>0]|0)){if(q<<24>>24!=3){e=m;break b}o=n+1|0;a[j+n>>0]=0;n=n+2|0;a[j+o>>0]=0;m=m+3|0;q=(c[k>>2]|0)+1|0;c[k>>2]=q;p=c[l>>2]|0;if((p|0)<(q|0)){p=p<<1;c[l>>2]=p;md(b,p,4)|0;p=c[b>>2]|0;if(!p){f=-12;break c}}else{p=c[b>>2]|0;if(!p)break}c[p+((c[k>>2]|0)+ -1<<2)>>2]=o}else{p=0;h=26}else h=26}else{a[j+n>>0]=a[d+m>>0]|0;a[j+(n+1)>>0]=a[d+(m+1)>>0]|0;p=a[p>>0]|0;n=n+2|0;m=o;h=26}while(0);if((h|0)==26){h=0;a[j+n>>0]=p;n=n+1|0;m=m+1|0}o=m+2|0;if((o|0)>=(e|0)){h=15;break b}}i=g;return f|0}else{n=m;h=15}while(0);if((h|0)==15)if((m|0)<(e|0)){h=e+n|0;k=m;while(1){a[j+n>>0]=a[d+k>>0]|0;k=k+1|0;if((k|0)==(e|0))break;else n=n+1|0}n=h-m|0}else e=m;h=j+n+0|0;d=h+32|0;do{a[h>>0]=0;h=h+1|0}while((h|0)<(d|0));c[f+12>>2]=j;c[f+8>>2]=n;q=e;i=g;return q|0}function Lb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;e=i;f=b+60|0;d=c[f>>2]|0;$c();cc();f=c[f>>2]|0;c[f+4>>2]=b;g=nd(31328)|0;c[f+136>>2]=g;if((((g|0)!=0?(c[f+72>>2]=g,c[f+8>>2]=f,g=hd(199)|0,c[f+152>>2]=g,(g|0)!=0):0)?(g=xd()|0,c[f+164>>2]=g,(g|0)!=0):0)?(h=xd()|0,c[f+2524>>2]=h,(h|0)!=0):0){c[f+2528>>2]=h;c[f+2592>>2]=2147483647;a[f+4469>>0]=1;c[f+2584>>2]=0;c[d+4368>>2]=0;c[d+4520>>2]=0;f=b+808|0;if(!(c[f>>2]&2))a[d+141>>0]=1;else a[d+141>>0]=c[b+800>>2];if((c[f>>2]&1|0)!=0?(c[b+800>>2]|0)>1:0){a[d+140>>0]=1;h=0;i=e;return h|0}a[d+140>>0]=2;h=0;i=e;return h|0}Nb(b)|0;h=-12;i=e;return h|0}function Mb(f,g,h,j){f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0,$a=0;k=i;i=i+16|0;m=k+8|0;n=k;l=c[f+60>>2]|0;f=j+28|0;J=c[f>>2]|0;if(!J){g=bc(l,g,1)|0;if((g|0)<0){Za=g;i=k;return Za|0}c[h>>2]=g;Za=0;i=k;return Za|0}q=l+2520|0;c[q>>2]=0;I=c[j+24>>2]|0;c[q>>2]=0;F=l+2584|0;z=l+2588|0;c[z>>2]=c[F>>2];c[F>>2]=0;v=l+4408|0;c[v>>2]=0;a:do if((J|0)>3){G=l+4470|0;E=l+4412|0;y=l+4404|0;u=l+4388|0;B=l+4396|0;w=l+4392|0;C=l+4384|0;x=l+4380|0;j=l+4376|0;t=l+136|0;s=l+2512|0;H=l+4480|0;while(1){A=(a[G>>0]|0)==0;if(A){while(1){K=I+1|0;if(((a[I>>0]|0)==0?(a[K>>0]|0)==0:0)?(a[I+2>>0]|0)==1:0)break;if((J|0)<5){p=-1094995529;o=180;break a}I=K;J=J+ -1|0}I=I+3|0;L=0;J=J+ -3|0}else{K=c[H>>2]|0;if((K|0)>0){M=0;L=0;do{M=d[I+L>>0]|M<<8;L=L+1|0}while((L|0)!=(K|0));L=M}else L=0;J=J-K|0;if((L|0)>(J|0)){p=-1094995529;o=180;break a}I=I+K|0}A=A?J:L;K=c[E>>2]|0;M=c[v>>2]|0;if((K|0)<(M+1|0)){K=K+1|0;L=ld(c[y>>2]|0,K,16)|0;if(!L){p=-12;o=180;break a}c[y>>2]=L;M=c[E>>2]|0;ae(L+(M<<4)|0,0,K-M<<4|0)|0;md(u,K,4)|0;md(B,K,4)|0;md(w,K,4)|0;M=c[B>>2]|0;c[M+(c[E>>2]<<2)>>2]=1024;M=pd(c[M+(c[E>>2]<<2)>>2]|0,4)|0;c[(c[w>>2]|0)+(c[E>>2]<<2)>>2]=M;c[E>>2]=K;M=c[v>>2]|0}c[C>>2]=c[(c[B>>2]|0)+(M<<2)>>2];c[x>>2]=c[(c[w>>2]|0)+(M<<2)>>2];L=c[y>>2]|0;K=Kb(l,I,A,L+(M<<4)|0)|0;c[(c[u>>2]|0)+(c[v>>2]<<2)>>2]=c[j>>2];c[(c[B>>2]|0)+(c[v>>2]<<2)>>2]=c[C>>2];Ya=c[x>>2]|0;Za=c[v>>2]|0;c[v>>2]=Za+1;c[(c[w>>2]|0)+(Za<<2)>>2]=Ya;if((K|0)<0){p=K;o=180;break a}Ya=c[t>>2]|0;Wa=c[L+(M<<4)+12>>2]|0;Xa=c[L+(M<<4)+8>>2]|0;Xa=Xa>>>0>268435455?-8:Xa<<3;Za=Xa>>>0>2147483639|(Wa|0)==0;Xa=Za?0:Xa;Wa=Za?0:Wa;A=Za?-1094995529:0;c[Ya+204>>2]=Wa;c[Ya+216>>2]=Xa;c[Ya+220>>2]=Xa+8;c[Ya+208>>2]=Wa+(Xa>>3);c[Ya+212>>2]=0;if(Za){p=A;o=180;break a}Qb(l)|0;if(((c[s>>2]|0)+ -36|0)>>>0<2)c[F>>2]=1;J=J-K|0;if((J|0)<=3)break;else I=I+K|0}if((c[v>>2]|0)>0){ka=l+4|0;Ea=l+1448|0;B=l+2046|0;Z=l+1428|0;Da=l+204|0;va=l+200|0;Ja=l+1449|0;Ka=l+1432|0;Oa=l+1436|0;Pa=l+2580|0;Ha=l+156|0;qa=l+1440|0;H=l+1450|0;K=l+1620|0;ua=l+2572|0;J=l+2516|0;L=l+2576|0;V=l+2056|0;W=l+2057|0;M=l+2058|0;O=l+2052|0;N=l+2048|0;Ma=l+2068|0;R=l+2072|0;P=l+2076|0;S=l+2080|0;X=l+2061|0;U=l+2084|0;T=l+2088|0;Y=l+2062|0;I=l+1451|0;Na=l+2108|0;Ia=l+2112|0;La=l+2500|0;ma=l+2592|0;na=l+2604|0;oa=l+4416|0;Ga=m+4|0;wa=l+4320|0;ya=l+2596|0;xa=l+2600|0;za=l+4324|0;Aa=l+4344|0;Ba=l+4348|0;Ca=l+4328|0;ra=l+160|0;pa=l+140|0;ta=l+164|0;_=l+2096|0;Q=l+2100|0;E=l+2104|0;F=l+141|0;G=l+4368|0;ba=l+2504|0;aa=l+2508|0;da=l+4332|0;ca=l+4336|0;ea=l+4340|0;ga=l+4352|0;fa=l+4316|0;ha=l+2608|0;ja=l+196|0;la=l+4364|0;ia=l+168|0;C=0;b:while(1){c[j>>2]=c[(c[u>>2]|0)+(C<<2)>>2];c[x>>2]=c[(c[w>>2]|0)+(C<<2)>>2];Ya=c[y>>2]|0;Xa=c[Ya+(C<<4)+12>>2]|0;Ya=c[Ya+(C<<4)+8>>2]|0;Za=c[t>>2]|0;Ya=Ya>>>0>268435455?-8:Ya<<3;Qa=Ya>>>0>2147483639|(Xa|0)==0;Ya=Qa?0:Ya;Xa=Qa?0:Xa;c[Za+204>>2]=Xa;c[Za+216>>2]=Ya;c[Za+220>>2]=Ya+8;c[Za+208>>2]=Xa+(Ya>>3);c[Za+212>>2]=0;c:do if(Qa){r=Qa?-1094995529:0;o=178}else{Qa=Qb(l)|0;d:do if((Qa|0)>=0){if(!Qa)break c;switch(c[s>>2]|0){case 37:case 36:{b[la>>1]=(e[la>>1]|0)+1&255;c[ma>>2]=2147483647;break c};case 48:{Qa=Fc(l)|0;if((Qa|0)<0)break d;else break c};case 40:case 39:{Qa=Ic(l)|0;if((Qa|0)<0)break d;else break c};case 9:case 8:case 7:case 6:case 21:case 20:case 19:case 18:case 17:case 16:case 5:case 4:case 3:case 2:case 0:case 1:{Qa=c[t>>2]|0;Ra=Qa+204|0;Za=(dd(Ra)|0)&255;a[Ea>>0]=Za;Sa=c[s>>2]|0;if(!((Sa+ -16|0)>>>0>4|Za<<24>>24==0)?(b[la>>1]=(e[la>>1]|0)+1&255,c[ma>>2]=2147483647,(Sa+ -19|0)>>>0<2):0){_b(l);Sa=c[s>>2]|0}a[B>>0]=0;if((Sa+ -16|0)>>>0<8)a[B>>0]=dd(Ra)|0;Sa=fd(Ra)|0;c[Z>>2]=Sa;if(Sa>>>0>255){p=A;o=180;break a}Sa=c[l+(Sa<<2)+400>>2]|0;if(!Sa){p=A;o=180;break a}if(!(a[Ea>>0]|0)){Va=c[Sa+4>>2]|0;if((c[Da>>2]|0)!=(Va|0)){p=A;o=180;break a}}else Va=c[Sa+4>>2]|0;c[Da>>2]=Va;Ta=c[s>>2]|0;Ua=(Ta|0)==21;if(Ua?(c[z>>2]|0)==1:0)a[B>>0]=1;Sa=c[va>>2]|0;Va=c[(c[l+(c[Va>>2]<<2)+272>>2]|0)+4>>2]|0;if((Sa|0)!=(Va|0)){c[va>>2]=Va;e:do if(Sa){if((Ta+ -16|0)>>>0>7|Ua)break;do if((c[Va+13120>>2]|0)==(c[Sa+13120>>2]|0)){if((c[Va+13124>>2]|0)!=(c[Sa+13124>>2]|0))break;if((c[Va+76+(((c[Va+72>>2]|0)+ -1|0)*12|0)>>2]|0)==(c[Sa+(((c[Sa+72>>2]|0)+ -1|0)*12|0)+76>>2]|0))break e}while(0);a[B>>0]=0}while(0);_b(l);Sa=c[va>>2]|0;Pb(l);Ua=c[Sa+13064>>2]|0;Va=Sa+13120|0;$a=c[Va>>2]|0;Wa=Sa+13124|0;_a=c[Wa>>2]|0;Ua=$((_a>>Ua)+1|0,($a>>Ua)+1|0)|0;Ta=$(c[Sa+13132>>2]|0,c[Sa+13128>>2]|0)|0;Za=Sa+13156|0;Ya=Sa+13160|0;Xa=$(c[Ya>>2]|0,c[Za>>2]|0)|0;c[ya>>2]=($a>>2)+1;c[xa>>2]=(_a>>2)+1;c[ba>>2]=qd(Ta,148)|0;_a=qd(Ta,8)|0;c[aa>>2]=_a;if((c[ba>>2]|0)==0|(_a|0)==0){o=71;break b}_a=Sa+13144|0;$a=Sa+13140|0;c[da>>2]=hd($(c[$a>>2]|0,c[_a>>2]|0)|0)|0;$a=pd(c[_a>>2]|0,c[$a>>2]|0)|0;c[ca>>2]=$a;if((c[da>>2]|0)==0|($a|0)==0){o=71;break b}c[Aa>>2]=pd(c[Sa+13148>>2]|0,c[Sa+13152>>2]|0)|0;c[ea>>2]=nd(Xa)|0;Xa=hd($((c[Ya>>2]|0)+1|0,(c[Za>>2]|0)+1|0)|0)|0;c[Ba>>2]=Xa;if(!(c[ea>>2]|0)){o=71;break b}if((c[Aa>>2]|0)==0|(Xa|0)==0){o=71;break b}c[ga>>2]=hd(Ta)|0;c[Ca>>2]=pd(Ua,4)|0;$a=pd(Ua,1)|0;c[fa>>2]=$a;if(!$a){o=71;break b}if(!(c[ga>>2]|0)){o=71;break b}if(!(c[Ca>>2]|0)){o=71;break b}c[wa>>2]=qd(c[ya>>2]|0,c[xa>>2]|0)|0;$a=qd(c[ya>>2]|0,c[xa>>2]|0)|0;c[za>>2]=$a;if((c[wa>>2]|0)==0|($a|0)==0){o=71;break b}$a=c[ka>>2]|0;c[$a+124>>2]=c[Va>>2];c[$a+128>>2]=c[Wa>>2];c[$a+116>>2]=c[Sa+12>>2];c[$a+120>>2]=c[Sa+16>>2];c[$a+136>>2]=c[Sa+60>>2];c[$a+172>>2]=c[Sa+(((c[Sa+72>>2]|0)+ -1|0)*12|0)+80>>2];$a=Sa+160|0;c[m+0>>2]=c[$a+0>>2];c[m+4>>2]=c[$a+4>>2];if(!(c[Sa+176>>2]|0)){Ta=c[ka>>2]|0;c[Ta+392>>2]=1}else{Ta=c[ka>>2]|0;c[Ta+392>>2]=(c[Sa+184>>2]|0)!=0?2:1}if(!(c[Sa+188>>2]|0)){c[Ta+380>>2]=2;c[Ta+384>>2]=2;c[Ta+388>>2]=2}else{c[Ta+380>>2]=d[Sa+192>>0];c[Ta+384>>2]=d[Sa+193>>0];c[Ta+388>>2]=d[Sa+194>>0]}dc(ha,c[Sa+52>>2]|0);if(a[Sa+12941>>0]|0){Ta=c[va>>2]|0;Ua=(c[Ta+4>>2]|0)!=0?3:1;$a=(1<>2])+2|0;$a=$($a,$a)|0;c[ia>>2]=hd($a<>2])|0;Ta=0;do{$a=c[va>>2]|0;_a=c[$a+13124>>2]>>c[$a+(Ta<<2)+13180>>2];Za=$(c[$a+13120>>2]>>c[$a+(Ta<<2)+13168>>2]<<1,c[$a+13132>>2]|0)|0;c[l+(Ta<<2)+172>>2]=hd(Za<>2])|0;$a=c[va>>2]|0;_a=$(_a<<1,c[$a+13128>>2]|0)|0;c[l+(Ta<<2)+184>>2]=hd(_a<>2])|0;Ta=Ta+1|0}while((Ta|0)<(Ua|0))}c[va>>2]=Sa;c[ja>>2]=c[(c[l+(c[Sa>>2]<<2)+208>>2]|0)+4>>2];b[la>>1]=(e[la>>1]|0)+1&255;c[ma>>2]=2147483647}$a=c[ka>>2]|0;c[$a+832>>2]=d[Sa+302>>0];c[$a+836>>2]=d[Sa+335>>0];a[Ja>>0]=0;do if(!(a[Ea>>0]|0)){if(a[(c[Da>>2]|0)+41>>0]|0){a[Ja>>0]=dd(Ra)|0;Sa=c[va>>2]|0}Sa=($(c[Sa+13128>>2]<<1,c[Sa+13132>>2]|0)|0)+ -2|0;Ta=Sa>>>0>65535;Sa=Ta?Sa>>>16:Sa;Ta=Ta?16:0;if(Sa&65280){Ta=Ta|8;Sa=Sa>>>8}Sa=ad(Ra,(d[4680+Sa>>0]|0)+Ta|0)|0;c[Ka>>2]=Sa;$a=c[va>>2]|0;if(Sa>>>0>=($(c[$a+13132>>2]|0,c[$a+13128>>2]|0)|0)>>>0){p=A;o=180;break a}if(a[Ja>>0]|0)if(!(a[Ha>>0]|0)){p=A;o=180;break a}else break;else{c[Oa>>2]=Sa;c[Pa>>2]=(c[Pa>>2]|0)+1;o=82;break}}else{c[Oa>>2]=0;c[Ka>>2]=0;c[Pa>>2]=0;a[Ha>>0]=0;o=82}while(0);f:do if((o|0)==82){o=0;a[Ha>>0]=0;if((c[(c[Da>>2]|0)+1624>>2]|0)>0){Sa=0;do{cd(Ra,1);Sa=Sa+1|0}while((Sa|0)<(c[(c[Da>>2]|0)+1624>>2]|0))}Sa=fd(Ra)|0;c[qa>>2]=Sa;if(Sa>>>0>=3){p=A;o=180;break a}if(!((Sa|0)==2?1:((c[s>>2]|0)+ -16|0)>>>0>7)){p=A;o=180;break a}a[H>>0]=1;if(a[(c[Da>>2]|0)+39>>0]|0)a[H>>0]=dd(Ra)|0;if(a[(c[va>>2]|0)+8>>0]|0)a[I>>0]=ad(Ra,2)|0;if(((c[s>>2]|0)+ -19|0)>>>0>=2){o=91;break b}c[K>>2]=0;c[ua>>2]=0;if(!(c[J>>2]|0))c[L>>2]=0;do if(a[(c[va>>2]|0)+12941>>0]|0){a[V>>0]=dd(Ra)|0;if(!(c[(c[va>>2]|0)+4>>2]|0)){a[W>>0]=0;a[M>>0]=0;break}else{$a=(dd(Ra)|0)&255;a[M>>0]=$a;a[W>>0]=$a;break}}else{a[V>>0]=0;a[W>>0]=0;a[M>>0]=0}while(0);c[O>>2]=0;c[N>>2]=0;c[Ma>>2]=gd(Ra)|0;Sa=c[Da>>2]|0;if(!(a[Sa+36>>0]|0)){c[R>>2]=0;c[P>>2]=0}else{c[R>>2]=gd(Ra)|0;c[P>>2]=gd(Ra)|0;Sa=c[Da>>2]|0}if(!(a[Sa+1631>>0]|0))a[S>>0]=0;else{a[S>>0]=dd(Ra)|0;Sa=c[Da>>2]|0}g:do if(!(a[Sa+55>>0]|0)){a[X>>0]=0;c[U>>2]=0;c[T>>2]=0}else{do if(a[Sa+56>>0]|0){if(!(dd(Ra)|0)){Sa=c[Da>>2]|0;break}$a=(dd(Ra)|0)&255;a[X>>0]=$a;if($a<<24>>24)break g;c[U>>2]=(gd(Ra)|0)<<1;c[T>>2]=(gd(Ra)|0)<<1;break g}while(0);a[X>>0]=a[Sa+57>>0]|0;c[U>>2]=c[Sa+60>>2];c[T>>2]=c[Sa+64>>2]}while(0);Sa=a[(c[Da>>2]|0)+54>>0]|0;h:do if(Sa<<24>>24){do if(!(a[V>>0]|0)){if(a[W>>0]|0)break;if(a[X>>0]|0)break h}while(0);a[Y>>0]=dd(Ra)|0;break f}while(0);a[Y>>0]=Sa}while(0);c[Na>>2]=0;$a=c[Da>>2]|0;if(!((a[$a+42>>0]|0)==0?(a[$a+43>>0]|0)==0:0))o=122;i:do if((o|0)==122){o=0;$a=fd(Ra)|0;c[Na>>2]=$a;if(($a|0)<=0){c[G>>2]=0;break}Sa=(fd(Ra)|0)+1|0;Ta=Sa>>4;Sa=Sa&15;kd(_);kd(Q);kd(E);c[_>>2]=pd(c[Na>>2]|0,4)|0;c[Q>>2]=pd(c[Na>>2]|0,4)|0;Ua=pd(c[Na>>2]|0,4)|0;c[E>>2]=Ua;if(!(c[_>>2]|0)){o=127;break b}if((c[Q>>2]|0)==0|(Ua|0)==0){o=127;break b}if((c[Na>>2]|0)>0){Wa=(Ta|0)>0;Va=(Sa|0)==0;Ua=0;do{if(Wa){Xa=0;Ya=0;do{Ya=(ad(Ra,16)|0)+(Ya<<16)|0;Xa=Xa+1|0}while((Xa|0)!=(Ta|0))}else Ya=0;if(!Va)Ya=(ad(Ra,Sa)|0)+(Ya<>2]|0)+(Ua<<2)>>2]=Ya+1;Ua=Ua+1|0}while((Ua|0)<(c[Na>>2]|0))}do if((d[F>>0]|0)>1){$a=c[Da>>2]|0;if((c[$a+48>>2]|0)<=1?(c[$a+44>>2]|0)<=1:0)break;c[G>>2]=0;a[F>>0]=1;break i}while(0);c[G>>2]=0}while(0);Sa=c[Da>>2]|0;if(a[Sa+1628>>0]|0){Sa=fd(Ra)|0;_a=be(Sa|0,0,3)|0;Ya=D;$a=(c[Qa+216>>2]|0)-(c[Qa+212>>2]|0)|0;Za=(($a|0)<0)<<31>>31;if((Ya|0)>(Za|0)|(Ya|0)==(Za|0)&_a>>>0>$a>>>0){p=A;o=180;break a}if(Sa){Ta=0;do{cd(Ra,8);Ta=Ta+1|0}while((Ta|0)!=(Sa|0))}Sa=c[Da>>2]|0}Ra=(c[Sa+16>>2]|0)+26+(c[Ma>>2]|0)|0;a[Ia>>0]=Ra;Ra=Ra<<24;if((Ra|0)>855638016){p=A;o=180;break a}if((Ra>>24|0)<(0-(c[(c[va>>2]|0)+13192>>2]|0)|0)){p=A;o=180;break a}$a=c[Ka>>2]|0;c[La>>2]=$a;if(($a|0)==0?(a[Ja>>0]|0)!=0:0){p=A;o=180;break a}if(((c[Qa+216>>2]|0)-(c[Qa+212>>2]|0)|0)<0){p=A;o=180;break a}a[(c[t>>2]|0)+203>>0]=(a[Ja>>0]|0)==0&1;if(!(a[(c[Da>>2]|0)+22>>0]|0))a[(c[t>>2]|0)+272>>0]=a[Ia>>0]|0;a[Ha>>0]=1;a[(c[t>>2]|0)+302>>0]=0;a[(c[t>>2]|0)+303>>0]=0;Ra=c[ma>>2]|0;Qa=c[s>>2]|0;j:do if((Ra|0)==2147483647)switch(Qa|0){case 18:case 16:case 17:case 21:{Ra=c[ua>>2]|0;c[ma>>2]=Ra;break j};case 20:case 19:{c[ma>>2]=-2147483648;Ra=-2147483648;break j};default:{Ra=2147483647;break j}}while(0);do if((Qa+ -8|0)>>>0<2){if((c[ua>>2]|0)<=(Ra|0)){c[na>>2]=0;break c}if((Qa|0)!=9)break;c[ma>>2]=-2147483648}while(0);k:do if(!(a[Ea>>0]|0)){if(!(c[q>>2]|0)){Qa=0;break d}}else{Ra=c[t>>2]|0;_a=c[va>>2]|0;Qa=c[_a+13064>>2]|0;$a=c[_a+13120>>2]>>Qa;Qa=(c[_a+13124>>2]>>Qa)+1|0;ae(c[wa>>2]|0,0,$(c[xa>>2]|0,c[ya>>2]|0)|0)|0;ae(c[za>>2]|0,0,$(c[xa>>2]|0,c[ya>>2]|0)|0)|0;_a=c[va>>2]|0;ae(c[Aa>>2]|0,0,$(c[_a+13152>>2]|0,c[_a+13148>>2]|0)|0)|0;_a=c[va>>2]|0;ae(c[Ba>>2]|0,0,$((c[_a+13160>>2]|0)+1|0,(c[_a+13156>>2]|0)+1|0)|0)|0;ae(c[Ca>>2]|0,-1,$(($a<<2)+4|0,Qa)|0)|0;c[na>>2]=0;c[oa>>2]=c[s>>2];Qa=c[Da>>2]|0;if(a[Qa+42>>0]|0)c[Ra+312>>2]=c[c[Qa+1648>>2]>>2]<>2]|0)+13080>>2];Qa=ac(l,ra,c[ua>>2]|0)|0;do if((Qa|0)>=0){c[(c[c[q>>2]>>2]|0)+80>>2]=((c[s>>2]|0)+ -16|0)>>>0<8&1;c[(c[ra>>2]|0)+84>>2]=3-(c[qa>>2]|0);zd(c[ta>>2]|0);Qa=bc(l,c[ta>>2]|0,0)|0;if((Qa|0)<0)break;break k}while(0);if(!(c[q>>2]|0)){o=167;break b}c[q>>2]=0;if((Qa|0)<0){p=A;break a}}while(0);if((c[s>>2]|0)!=(c[oa>>2]|0)){p=A;o=180;break a}c[m>>2]=0;c[Ga>>2]=1;Qa=c[ka>>2]|0;Fa[c[Qa+816>>2]&1](Qa,1,m,n,1,4)|0;Qa=c[n>>2]|0;$a=c[va>>2]|0;if((Qa|0)>=($(c[$a+13132>>2]|0,c[$a+13128>>2]|0)|0))c[na>>2]=1;if((Qa|0)<0)break d;else break c};case 34:{Qa=Gc(l)|0;if((Qa|0)<0)break d;else break c};default:break c}}while(0);r=(c[(c[ka>>2]|0)+688>>2]&8|0)==0?0:Qa;o=178}while(0);if((o|0)==178?(o=0,(r|0)<0):0){p=A;o=180;break a}C=C+1|0;if((C|0)>=(c[v>>2]|0)){p=A;o=180;break a}}if((o|0)==71){Pb(l);Pb(l);c[va>>2]=0;p=A;o=180;break}else if((o|0)==91)sa();else if((o|0)==127){c[Na>>2]=0;p=A;o=180;break}else if((o|0)==167){c[q>>2]=0;p=A;break}}else{p=A;o=180}}else{p=0;o=180}while(0);if((p|0)<0){$a=p;i=k;return $a|0}m=l+2604|0;if(c[m>>2]|0)c[m>>2]=0;l=c[l+164>>2]|0;if(c[l+304>>2]|0){Ad(g,l);c[h>>2]=1}$a=c[f>>2]|0;i=k;return $a|0}function Nb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;e=c[b+60>>2]|0;Pb(e);b=e+4412|0;f=e+4392|0;if((c[b>>2]|0)>0){g=0;do{kd((c[f>>2]|0)+(g<<2)|0);g=g+1|0}while((g|0)<(c[b>>2]|0))}kd(e+4396|0);kd(e+4388|0);kd(f);kd(e+152|0);kd(e+168|0);kd(e+172|0);kd(e+184|0);kd(e+176|0);kd(e+188|0);kd(e+180|0);kd(e+192|0);yd(e+164|0);g=e+2524|0;Zb(e,g,-1);yd(g);g=e+208|0;f=0;do{wd(g+(f<<2)|0);f=f+1|0}while((f|0)!=16);g=e+272|0;f=0;do{wd(g+(f<<2)|0);f=f+1|0}while((f|0)!=32);f=e+400|0;g=0;do{wd(f+(g<<2)|0);g=g+1|0}while((g|0)!=256);c[e+200>>2]=0;c[e+204>>2]=0;c[e+196>>2]=0;wd(e+1424|0);kd(e+2096|0);kd(e+2100|0);kd(e+2104|0);h=e+141|0;l=a[h>>0]|0;f=e+72|0;if((l&255)>1){g=e+8|0;j=1;do{k=f+(j<<2)|0;if(c[k>>2]|0){kd(k);kd(g+(j<<2)|0);l=a[h>>0]|0}j=j+1|0}while((j|0)<(l&255|0))}g=e+136|0;if((c[g>>2]|0)==(c[f>>2]|0))c[g>>2]=0;kd(f);f=e+4404|0;if((c[b>>2]|0)<=0){kd(f);c[b>>2]=0;i=d;return 0}e=0;do{kd((c[f>>2]|0)+(e<<4)|0);e=e+1|0}while((e|0)<(c[b>>2]|0));kd(f);c[b>>2]=0;i=d;return 0}function Ob(a){a=a|0;var b=0;b=i;a=c[a+60>>2]|0;$b(a);c[a+2592>>2]=2147483647;i=b;return}function Pb(a){a=a|0;var b=0;b=i;kd(a+2504|0);kd(a+2508|0);kd(a+4332|0);kd(a+4336|0);kd(a+4340|0);kd(a+4344|0);kd(a+4348|0);kd(a+4316|0);kd(a+4328|0);kd(a+4352|0);kd(a+4320|0);kd(a+4324|0);kd(a+2096|0);kd(a+2104|0);kd(a+2100|0);i=b;return}function Qb(a){a=a|0;var b=0,d=0,e=0;b=i;d=(c[a+136>>2]|0)+204|0;if(dd(d)|0){e=-1094995529;i=b;return e|0}c[a+2512>>2]=ad(d,6)|0;e=ad(d,6)|0;d=(ad(d,3)|0)+ -1|0;c[a+2516>>2]=d;if((d|0)<0){e=-1094995529;i=b;return e|0}e=(e|0)==0&1;i=b;return e|0}function Rb(e,f){e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0;f=i;h=c[e+60>>2]|0;k=h+200|0;E=c[k>>2]|0;e=1<>2];l=h+204|0;n=c[l>>2]|0;A=c[(c[n+1668>>2]|0)+(c[h+2500>>2]<<2)>>2]|0;m=(a[h+1449>>0]|0)==0;if(!A)if(m)g=4;else{W=-1094995529;i=f;return W|0}else if(!m){m=h+4328|0;r=h+1436|0;if((c[(c[m>>2]|0)+(c[(c[n+1672>>2]|0)+(A+ -1<<2)>>2]<<2)>>2]|0)!=(c[r>>2]|0)){W=-1094995529;i=f;return W|0}}else g=4;if((g|0)==4){m=h+4328|0;r=h+1436|0}q=e+ -1|0;s=h+136|0;p=h+2504|0;y=h+2056|0;o=h+2057|0;w=h+2084|0;x=h+2508|0;v=h+2088|0;u=h+2062|0;t=h+4352|0;z=0;n=0;do{if((A|0)>=(c[E+13136>>2]|0))break;G=c[l>>2]|0;B=c[(c[G+1672>>2]|0)+(A<<2)>>2]|0;J=E+13120|0;I=E+13080|0;H=c[I>>2]|0;n=q+(c[J>>2]|0)>>H;z=((B|0)%(n|0)|0)<>2]|0;H=1<>2]|0;D=B-F|0;c[(c[m>>2]|0)+(B<<2)>>2]=F;do if(!(a[G+43>>0]|0)){if(!(a[G+42>>0]|0)){c[C+312>>2]=c[J>>2];G=E;break}if((A|0)!=0?(W=c[G+1676>>2]|0,(c[W+(A<<2)>>2]|0)!=(c[W+(A+ -1<<2)>>2]|0)):0){W=c[I>>2]|0;c[C+312>>2]=(c[(c[G+1648>>2]|0)+(c[(c[G+1664>>2]|0)+(z>>W<<2)>>2]<<2)>>2]<>0]=1;G=c[k>>2]|0}else G=E}else{if((z|0)==0?(H+ -1&n|0)==0:0){a[C+203>>0]=1;E=c[k>>2]|0}c[C+312>>2]=c[E+13120>>2];G=E}while(0);E=H+n|0;H=c[G+13124>>2]|0;c[C+316>>2]=(E|0)>(H|0)?H:E;E=C+31312|0;c[E>>2]=0;H=c[l>>2]|0;if(!(a[H+42>>0]|0)){if((B|0)==(F|0)){c[E>>2]=1;F=1}else F=0;if((D|0)<(c[G+13128>>2]|0)){F=F|4;c[E>>2]=F}}else{if((z|0)>0){W=c[H+1676>>2]|0;I=B+ -1|0;if((c[W+(A<<2)>>2]|0)==(c[W+(c[(c[H+1668>>2]|0)+(I<<2)>>2]<<2)>>2]|0))F=0;else{c[E>>2]=2;F=2}W=c[m>>2]|0;if((c[W+(B<<2)>>2]|0)!=(c[W+(I<<2)>>2]|0)){F=F|1;c[E>>2]=F}}else F=0;if((n|0)>0){W=c[H+1676>>2]|0;I=G+13128|0;G=c[I>>2]|0;if((c[W+(A<<2)>>2]|0)!=(c[W+(c[(c[H+1668>>2]|0)+(B-G<<2)>>2]<<2)>>2]|0)){F=F|8;c[E>>2]=F;G=c[I>>2]|0}W=c[m>>2]|0;if((c[W+(B<<2)>>2]|0)!=(c[W+(B-G<<2)>>2]|0)){F=F|4;c[E>>2]=F}}}E=(z|0)>0;if(E&(D|0)>0)G=(F>>>1&1^1)&255;else G=0;a[C+308>>0]=G;if((n|0)>0){if((D|0)<(c[(c[k>>2]|0)+13128>>2]|0))F=0;else F=(F>>>3&1^1)&255;a[C+309>>0]=F;F=c[(c[k>>2]|0)+13128>>2]|0;if((D+1|0)<(F|0))F=0;else{W=c[l>>2]|0;V=c[W+1676>>2]|0;F=(c[V+(A<<2)>>2]|0)==(c[V+(c[(c[W+1668>>2]|0)+(B+1-F<<2)>>2]<<2)>>2]|0)&1}a[C+310>>0]=F;if(E?(j=c[(c[k>>2]|0)+13128>>2]|0,(D|0)>(j|0)):0){D=c[l>>2]|0;W=c[D+1676>>2]|0;D=(c[W+(A<<2)>>2]|0)==(c[W+(c[(c[D+1668>>2]|0)+(B+ -1-j<<2)>>2]<<2)>>2]|0)&1}else D=0}else{a[C+309>>0]=0;a[C+310>>0]=0;D=0}a[C+311>>0]=D;Wa(h,A);D=c[k>>2]|0;E=c[D+13080>>2]|0;F=z>>E;E=n>>E;G=c[s>>2]|0;D=($(c[D+13128>>2]|0,E)|0)+F|0;C=c[p>>2]|0;if((a[y>>0]|0)==0?(a[o>>0]|0)==0:0){M=0;H=0}else{if((F|0)>0?(a[G+308>>0]|0)!=0:0)M=$a(h)|0;else M=0;if((E|0)>0&(M|0)==0)if(!(a[G+309>>0]|0)){M=0;H=0}else{M=0;H=($a(h)|0)!=0}else H=0}I=(c[(c[k>>2]|0)+4>>2]|0)!=0?3:1;L=C+(D*148|0)+143|0;G=C+(D*148|0)+144|0;K=C+(D*148|0)+104|0;J=C+(D*148|0)+108|0;R=(M|0)==0;S=R&(H^1);M=E+ -1|0;O=F+ -1|0;P=0;do{Q=c[l>>2]|0;Q=d[((P|0)==0?Q+1644|0:Q+1645|0)>>0]|0;a:do if(a[h+P+2056>>0]|0){T=(P|0)==2;do if(!T){if(S){U=(bb(h)|0)&255;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}if(!R){U=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;U=a[(c[p>>2]|0)+(U*148|0)+P+142>>0]|0;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}if(H){U=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;U=a[(c[p>>2]|0)+(U*148|0)+P+142>>0]|0;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}else{a[C+(D*148|0)+P+142>>0]=0;break a}}else{U=a[L>>0]|0;a[G>>0]=U;c[J>>2]=c[K>>2];N=G}while(0);if(U<<24>>24){U=0;do{do if(!S){if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(U<<2)>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(U<<2)>>2];break}else{c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=0;break}}else c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=eb(h)|0;while(0);U=U+1|0}while((U|0)!=4);do if((a[N>>0]|0)==1){T=0;do{do if(c[C+(D*148|0)+(P<<4)+(T<<2)>>2]|0){if(S){c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=fb(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(T<<2)+48>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(T<<2)+48>>2];break}else{c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=0;break}}else c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=0;while(0);T=T+1|0}while((T|0)!=4);if(S){a[C+(D*148|0)+P+96>>0]=db(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;a[C+(D*148|0)+P+96>>0]=a[(c[p>>2]|0)+(W*148|0)+P+96>>0]|0;break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;a[C+(D*148|0)+P+96>>0]=a[(c[p>>2]|0)+(W*148|0)+P+96>>0]|0;break}else{a[C+(D*148|0)+P+96>>0]=0;break}}else if(!T){if(S){c[C+(D*148|0)+(P<<2)+100>>2]=gb(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<2)+100>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<2)+100>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<2)+100>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<2)+100>>2];break}else{c[C+(D*148|0)+(P<<2)+100>>2]=0;break}}while(0);b[C+(D*148|0)+(P*10|0)+112>>1]=0;T=0;do{W=c[C+(D*148|0)+(P<<4)+(T<<2)>>2]|0;V=T;T=T+1|0;U=C+(D*148|0)+(P*10|0)+(T<<1)+112|0;b[U>>1]=W;if((a[N>>0]|0)==2){if((V|0)>1){W=0-W|0;b[U>>1]=W}}else if(c[C+(D*148|0)+(P<<4)+(V<<2)+48>>2]|0){W=0-W|0;b[U>>1]=W}b[U>>1]=W<<16>>16<>0]=0;while(0);P=P+1|0}while((P|0)<(I|0));C=c[x>>2]|0;c[C+(B<<3)>>2]=c[w>>2];c[C+(B<<3)+4>>2]=c[v>>2];a[(c[t>>2]|0)+B>>0]=a[u>>0]|0;C=Sb(h,z,n,c[(c[k>>2]|0)+13080>>2]|0,0)|0;if((C|0)<0){g=108;break}A=A+1|0;Va(h,A);Fb(h,z,n,e);E=c[k>>2]|0}while((C|0)!=0);if((g|0)==108){c[(c[m>>2]|0)+(B<<2)>>2]=-1;W=C;i=f;return W|0}if((z+e|0)<(c[E+13120>>2]|0)){W=A;i=f;return W|0}if((n+e|0)<(c[E+13124>>2]|0)){W=A;i=f;return W|0}Db(h,z,n,e);W=A;i=f;return W|0}function Sb(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0;j=i;i=i+32|0;z=j;B=j+20|0;A=b+136|0;r=c[A>>2]|0;l=1<>2]|0;q=b+204|0;s=c[q>>2]|0;p=(1<<(c[t+13080>>2]|0)-(c[s+24>>2]|0))+ -1|0;c[r+31232>>2]=h;k=l+e|0;if(((k|0)<=(c[t+13120>>2]|0)?(l+f|0)<=(c[t+13124>>2]|0):0)?(c[t+13064>>2]|0)>>>0>>0:0){t=nb(b,h,e,f)|0;s=c[q>>2]|0}else t=(c[t+13064>>2]|0)>>>0>>0&1;if((a[s+22>>0]|0)!=0?((c[(c[m>>2]|0)+13080>>2]|0)-(c[s+24>>2]|0)|0)>>>0<=g>>>0:0){a[r+300>>0]=0;c[r+280>>2]=0}if((a[b+2080>>0]|0)!=0?((c[(c[m>>2]|0)+13080>>2]|0)-(d[(c[q>>2]|0)+1632>>0]|0)|0)>>>0<=g>>>0:0)a[r+301>>0]=0;if(t){n=l>>1;o=n+e|0;q=n+f|0;g=g+ -1|0;h=h+1|0;s=Sb(b,e,f,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}if(s){if((o|0)<(c[(c[m>>2]|0)+13120>>2]|0)){s=Sb(b,o,f,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}if(s){if((q|0)<(c[(c[m>>2]|0)+13124>>2]|0)){s=Sb(b,e,q,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}if(s){X=c[m>>2]|0;if((o|0)<(c[X+13120>>2]|0)?(q|0)<(c[X+13124>>2]|0):0){s=Sb(b,o,q,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}}else s=0}else s=0}else s=0;if((p&k|0)==0?(p&l+f|0)==0:0)c[r+276>>2]=a[r+272>>0];if(!s){X=0;i=j;return X|0}k=c[m>>2]|0;if((o+n|0)<(c[k+13120>>2]|0))k=1;else k=(q+n|0)<(c[k+13124>>2]|0);X=k&1;i=j;return X|0}p=c[A>>2]|0;s=c[m>>2]|0;r=c[s+13064>>2]|0;h=c[s+13140>>2]|0;s=1<<(c[s+13080>>2]|0)-(c[(c[q>>2]|0)+24>>2]|0);c[p+31236>>2]=e;c[p+31240>>2]=f;y=p+31252|0;a[y>>0]=1;v=p+31244|0;c[v>>2]=1;E=p+31248|0;c[E>>2]=0;w=p+31254|0;a[w>>0]=0;x=p+31253|0;a[x>>0]=0;t=($(f>>r,h)|0)+(e>>r)|0;H=b+4332|0;a[(c[H>>2]|0)+t>>0]=0;X=p+31268|0;a[X>>0]=1;a[X+1>>0]=1;a[X+2>>0]=1;a[X+3>>0]=1;r=l>>r;s=s+ -1|0;if(a[(c[q>>2]|0)+40>>0]|0){X=(ib(b)|0)&255;a[p+31256>>0]=X;if(X<<24>>24)Tb(b,e,f,g)}else a[p+31256>>0]=0;u=(r|0)>0;if(u){G=t;F=0;while(1){ae((c[H>>2]|0)+G|0,0,r|0)|0;F=F+1|0;if((F|0)==(r|0))break;else G=G+h|0}}if((c[v>>2]|0)==1?(c[(c[m>>2]|0)+13064>>2]|0)!=(g|0):0)C=c[E>>2]|0;else{F=ob(b,g)|0;c[E>>2]=F;E=c[v>>2]|0;if((F|0)==3)G=(E|0)==1&1;else G=0;a[w>>0]=G;if((E|0)==1)C=F;else sa()}if((((C|0)==0?(D=c[m>>2]|0,(c[D+68>>2]|0)!=0):0)?(c[D+13048>>2]|0)>>>0<=g>>>0:0)?(c[D+13052>>2]|0)>>>0>=g>>>0:0){C=(pb(b)|0)&255;a[x>>0]=C}else C=a[x>>0]|0;do if(!(C<<24>>24)){C=c[A>>2]|0;F=(c[C+31248>>2]|0)==3;D=F?2:1;H=0;do{G=H<<1;E=0;do{a[B+(E+G)>>0]=qb(b)|0;E=E+1|0}while((E|0)<(D|0));H=H+1|0}while((H|0)<(D|0));Q=l>>(F&1);P=C+31264|0;R=z+4|0;E=z+8|0;F=b+4340|0;O=C+31260|0;N=0;do{J=N<<1;H=($(N,Q)|0)+f|0;I=0;do{L=I+J|0;U=(a[B+L>>0]|0)==0;if(U)c[P>>2]=sb(b)|0;else c[O>>2]=rb(b)|0;V=($(I,Q)|0)+e|0;T=c[A>>2]|0;X=c[m>>2]|0;S=c[X+13084>>2]|0;M=V>>S;K=H>>S;G=c[X+13156>>2]|0;S=Q>>S;X=c[X+13080>>2]|0;W=(1<>0]|0)==0?(W&H|0)==0:0)W=1;else{W=($(K+ -1|0,G)|0)+M|0;W=d[(c[F>>2]|0)+W>>0]|0}if((a[T+308>>0]|0)==0&(V|0)==0)V=1;else{V=M+ -1+($(K,G)|0)|0;V=d[(c[F>>2]|0)+V>>0]|0}X=(H>>X<>>0<2){c[z>>2]=0;c[R>>2]=1;c[E>>2]=26;V=0;X=1;W=26;break}else{c[z>>2]=V;X=(V+29&31)+2|0;c[R>>2]=X;W=(V+31&31)+2|0;c[E>>2]=W;break}else{c[z>>2]=V;c[R>>2]=X;if(!((V|0)==0|(X|0)==0)){c[E>>2]=0;W=0;break}if((V|0)==1|(X|0)==1){c[E>>2]=26;W=26;break}else{c[E>>2]=1;W=1;break}}while(0);if(U){if((V|0)>(X|0)){c[R>>2]=V;U=X&255;c[z>>2]=U}else{U=V;V=X}if((U|0)>(W|0)){c[E>>2]=U;X=W&255;c[z>>2]=X;W=U;U=X}if((V|0)>(W|0)){c[E>>2]=V;X=W&255;c[R>>2]=X}else{X=V;V=W}T=c[T+31264>>2]|0;T=((T|0)>=(U|0)&1)+T|0;T=((T|0)>=(X|0)&1)+T|0;T=((T|0)>=(V|0)&1)+T|0}else T=c[z+(c[T+31260>>2]<<2)>>2]|0;S=(S|0)==0?1:S;T=T&255;if((S|0)>0){U=0;do{X=($(U+K|0,G)|0)+M|0;ae((c[F>>2]|0)+X|0,T|0,S|0)|0;U=U+1|0}while((U|0)<(S|0))}a[C+L+31268>>0]=T;I=I+1|0}while((I|0)<(D|0));N=N+1|0}while((N|0)<(D|0));z=c[(c[m>>2]|0)+4>>2]|0;if(!z)break;else if((z|0)==2){A=tb(b)|0;a[C+31281>>0]=A;z=a[C+31268>>0]|0;if((A|0)==4)z=z&255;else{X=a[1528+A>>0]|0;z=z<<24>>24==X<<24>>24?34:X&255}a[C+31277>>0]=a[1536+z>>0]|0;break}else if((z|0)!=3){A=tb(b)|0;z=a[C+31268>>0]|0;if((A|0)==4){a[C+31277>>0]=z;break}A=a[1528+A>>0]|0;B=C+31277|0;if(z<<24>>24==A<<24>>24){a[B>>0]=34;break}else{a[B>>0]=A;break}}else{A=0;do{B=A<<1;E=0;do{G=tb(b)|0;F=E+B|0;a[C+F+31281>>0]=G;z=a[C+F+31268>>0]|0;do if((G|0)!=4){G=a[1528+G>>0]|0;F=C+F+31277|0;if(z<<24>>24==G<<24>>24){a[F>>0]=34;break}else{a[F>>0]=G;break}}else a[C+F+31277>>0]=z;while(0);E=E+1|0}while((E|0)<(D|0));A=A+1|0}while((A|0)<(D|0))}}else{G=c[m>>2]|0;E=c[G+13084>>2]|0;B=l>>E;D=c[G+13156>>2]|0;C=e>>E;E=f>>E;B=(B|0)==0?1:B;if((B|0)>0){F=b+4340|0;G=0;do{X=($(G+E|0,D)|0)+C|0;ae((c[F>>2]|0)+X|0,1,B|0)|0;G=G+1|0}while((G|0)<(B|0));G=c[m>>2]|0}I=c[A>>2]|0;V=c[b+160>>2]|0;C=c[V+32>>2]|0;F=$(C,f)|0;H=c[G+56>>2]|0;F=(c[V>>2]|0)+((e<>2]|0;K=c[G+13184>>2]|0;B=$(f>>K,D)|0;J=c[G+13172>>2]|0;B=(c[V+4>>2]|0)+((e>>J<>2]|0;X=c[G+13188>>2]|0;E=$(f>>X,A)|0;W=c[G+13176>>2]|0;E=(c[V+8>>2]|0)+((e>>W<>0]|0,l<>W,l>>X)|0)+($(l>>J,l>>K)|0)|0;G=($(d[G+13045>>0]|0,K)|0)+H|0;H=I+224|0;K=G+7>>3;J=c[I+240>>2]|0;X=c[H>>2]|0;J=(X&1|0)==0?J:J+ -1|0;J=(X&511|0)==0?J:J+ -1|0;I=(c[I+244>>2]|0)-J|0;if((I|0)<(K|0))J=0;else _c(H,J+K|0,I-K|0);if(!(a[b+2061>>0]|0))Cb(b,e,f,g);X=G>>>0>2147483639|(J|0)==0;W=X?0:G;V=X?0:J;c[z>>2]=V;c[z+12>>2]=W;c[z+16>>2]=W+8;c[z+4>>2]=V+(W+7>>3);c[z+8>>2]=0;if(X)z=-1094995529;else{W=b+2608|0;X=c[m>>2]|0;Ba[c[W>>2]&7](F,C,l,l,z,d[X+13044>>0]|0,c[X+52>>2]|0);X=c[m>>2]|0;Ba[c[W>>2]&7](B,D,l>>c[X+13172>>2],l>>c[X+13184>>2],z,d[X+13045>>0]|0,c[X+52>>2]|0);X=c[m>>2]|0;Ba[c[W>>2]&7](E,A,l>>c[X+13176>>2],l>>c[X+13188>>2],z,d[X+13045>>0]|0,c[X+52>>2]|0);z=0}if(a[(c[m>>2]|0)+13056>>0]|0)Tb(b,e,f,g);if((z|0)<0){X=z;i=j;return X|0}}while(0);do if(!(a[x>>0]|0)){if(!(a[y>>0]|0)){if(a[b+2061>>0]|0)break;Cb(b,e,f,g);break}x=c[m>>2]|0;if((c[v>>2]|0)==1)v=(d[w>>0]|0)+(c[x+13092>>2]|0)|0;else v=c[x+13088>>2]|0;a[p+31255>>0]=v;v=Ub(b,e,f,e,f,e,f,g,g,0,0,1520,1520)|0;if((v|0)<0){X=v;i=j;return X|0}}while(0);if((a[(c[q>>2]|0)+22>>0]|0)!=0?(a[p+300>>0]|0)==0:0)Bb(b,e,f,g);if(u){q=b+4316|0;g=p+272|0;u=0;while(1){ae((c[q>>2]|0)+t|0,a[g>>0]|0,r|0)|0;u=u+1|0;if((u|0)==(r|0))break;else t=t+h|0}}if((s&k|0)==0?(s&l+f|0)==0:0)c[p+276>>2]=a[p+272>>0];q=c[m>>2]|0;X=c[q+13064>>2]|0;g=l>>X;r=e>>X;e=f>>X;if((g|0)>0?(n=b+4336|0,o=c[p+31232>>2]&255,X=($(c[q+13140>>2]|0,e)|0)+r|0,ae((c[n>>2]|0)+X|0,o|0,g|0)|0,(g|0)!=1):0){p=1;do{X=($(c[(c[m>>2]|0)+13140>>2]|0,p+e|0)|0)+r|0;ae((c[n>>2]|0)+X|0,o|0,g|0)|0;p=p+1|0}while((p|0)!=(g|0))}e=c[m>>2]|0;m=1<>2];if(((k|0)%(m|0)|0|0)!=0?(k|0)<(c[e+13120>>2]|0):0){X=1;i=j;return X|0}X=l+f|0;if(((X|0)%(m|0)|0|0)!=0?(X|0)<(c[e+13124>>2]|0):0){X=1;i=j;return X|0}X=(hb(b)|0)==0&1;i=j;return X|0}function Tb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;m=1<>2]|0;l=c[n+13084>>2]|0;f=c[n+13156>>2]|0;k=m+d|0;j=c[n+13120>>2]|0;m=m+e|0;n=c[n+13124>>2]|0;h=e>>l;e=((m|0)>(n|0)?n:m)>>l;if((h|0)>=(e|0)){i=g;return}d=d>>l;j=((k|0)>(j|0)?j:k)>>l;k=(d|0)<(j|0);b=b+4348|0;do{if(k){m=$(h,f)|0;l=d;do{a[(c[b>>2]|0)+(l+m)>>0]=2;l=l+1|0}while((l|0)!=(j|0))}h=h+1|0}while((h|0)!=(e|0));i=g;return}function Ub(e,f,g,h,j,k,l,m,n,o,p,q,r){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;var s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;s=i;i=i+16|0;w=s+8|0;t=s;z=e+136|0;v=c[z>>2]|0;K=c[q>>2]|0;c[w>>2]=K;A=c[q+4>>2]|0;G=w+4|0;c[G>>2]=A;L=c[r>>2]|0;c[t>>2]=L;q=c[r+4>>2]|0;x=t+4|0;c[x>>2]=q;y=a[v+31254>>0]|0;do if(y<<24>>24){if((o|0)==1){c[v+288>>2]=d[v+p+31268>>0];if((c[(c[e+200>>2]|0)+4>>2]|0)==3){c[v+292>>2]=d[v+p+31277>>0];c[v+296>>2]=d[v+p+31281>>0];break}else{c[v+292>>2]=d[v+31277>>0];c[v+296>>2]=d[v+31281>>0];break}}}else{c[v+288>>2]=d[v+31268>>0];c[v+292>>2]=d[v+31277>>0];c[v+296>>2]=d[v+31281>>0]}while(0);r=e+200|0;I=c[r>>2]|0;B=(c[I+13076>>2]|0)>>>0>>0;if(((!B?(c[I+13072>>2]|0)>>>0>>0:0)?(d[v+31255>>0]|0)>(o|0):0)?!(y<<24>>24!=0&(o|0)==0):0)y=(ub(e,n)|0)&255;else{if((c[I+13088>>2]|0)==0?(c[v+31244>>2]|0)==0:0)I=(o|0)==0&(c[v+31248>>2]|0)!=0;else I=0;if(B)y=1;else y=(y<<24>>24!=0&(o|0)==0|I)&1}B=(n|0)>2;I=c[(c[r>>2]|0)+4>>2]|0;if(B)if(!I){J=q;M=A}else E=20;else if((I|0)==3)E=20;else{J=q;M=A}do if((E|0)==20){I=(o|0)==0;if(!((K|0)==0&(I^1))){K=vb(e,o)|0;c[w>>2]=K;if((c[(c[r>>2]|0)+4>>2]|0)==2?y<<24>>24==0|(n|0)==3:0){A=vb(e,o)|0;c[G>>2]=A}if(!I)E=25}else{K=0;E=25}if((E|0)==25)if(!L){L=0;J=q;M=A;break}L=vb(e,o)|0;c[t>>2]=L;if((c[(c[r>>2]|0)+4>>2]|0)==2?y<<24>>24==0|(n|0)==3:0){J=vb(e,o)|0;c[x>>2]=J;M=A}else{J=q;M=A}}while(0);if(!(y<<24>>24)){A=c[r>>2]|0;q=c[A+13072>>2]|0;y=1<>2]|0;if(((o|0)==0?(c[v+31244>>2]|0)!=1:0)&(K|0)==0&(L|0)==0)if((c[A+4>>2]|0)==2?(M|J|0)!=0:0)E=37;else o=1;else E=37;if((E|0)==37){o=wb(e,o)|0;A=c[r>>2]|0}G=c[z>>2]|0;A=n-(c[A+13172>>2]|0)|0;z=G+31244|0;if((c[z>>2]|0)==1){I=1<>2]|0;L=c[K+4>>2]|0;if((L|0)==2){if(M){E=46;break}if(J){M=0;E=46;break}}if(!((c[z>>2]|0)!=1|(L|0)==0)){if(B|(L|0)==3){t=1<<(c[K+13172>>2]|0)+A;w=1<<(c[K+13184>>2]|0)+A;Ec(e,f,g,t,w);Wb(e,f,g,A,1);Wb(e,f,g,A,2);if((c[(c[r>>2]|0)+4>>2]|0)!=2)break;M=(1<>2]|0)+n,Ec(e,h,j,H,F),Wb(e,h,j,n,1),Wb(e,h,j,n,2),(c[(c[r>>2]|0)+4>>2]|0)==2):0){M=(1<>2]|0)+4>>2]|0)==2){F=(M|J|0)==0;E=48}else{F=1;E=48}a:do if((E|0)==48){E=e+204|0;do if((a[(c[E>>2]|0)+22>>0]|0)!=0?(D=G+300|0,(a[D>>0]|0)==0):0){M=jb(e)|0;H=G+280|0;c[H>>2]=M;if(M){M=(kb(e)|0)==1;J=c[H>>2]|0;if(M){J=0-J|0;c[H>>2]=J}}else J=0;a[D>>0]=1;M=(c[(c[r>>2]|0)+13192>>2]|0)/2|0;if((J|0)<(-26-M|0)|(J|0)>(M+25|0)){M=-1094995529;i=s;return M|0}else{Bb(e,k,l,m);break}}while(0);if((!((a[e+2080>>0]|0)==0|F)?(a[G+31256>>0]|0)==0:0)?(C=G+301|0,(a[C>>0]|0)==0):0){if(!(lb(e)|0)){a[G+302>>0]=0;a[G+303>>0]=0}else{k=c[E>>2]|0;if(!(a[k+1633>>0]|0))l=0;else{l=mb(e)|0;k=c[E>>2]|0}a[G+302>>0]=a[k+l+1634>>0]|0;a[G+303>>0]=a[(c[E>>2]|0)+l+1639>>0]|0}a[C>>0]=1}if((c[z>>2]|0)==1&(n|0)<4){k=c[G+288>>2]|0;if((k+ -6|0)>>>0<9)m=2;else m=(k+ -22|0)>>>0<9&1;k=c[G+292>>2]|0;if((k+ -6|0)>>>0<9)k=2;else k=(k+ -22|0)>>>0<9&1}else{m=0;k=0}l=G+304|0;a[l>>0]=0;if(I)zb(e,f,g,n,m,0);m=c[r>>2]|0;C=c[m+4>>2]|0;if(C){if(!(B|(C|0)==3)){if((p|0)!=3)break;p=1<>2]|0)+n;l=0;do{if((c[z>>2]|0)==1){M=(l<>2]|0)zb(e,h,(l<>2]|0)+4>>2]|0)==2?2:1)|0));w=0;while(1){if((c[z>>2]|0)==1){M=(w<>2]|0)zb(e,h,(w<=(((c[(c[r>>2]|0)+4>>2]|0)==2?2:1)|0))break a}}j=1<<(c[m+13172>>2]|0)+A;h=1<<(c[m+13184>>2]|0)+A;do if((a[(c[E>>2]|0)+1630>>0]|0)==0|I^1)a[l>>0]=0;else{if(c[z>>2]|0){M=(c[G+296>>2]|0)==4;a[l>>0]=M&1;if(!M)break}else a[l>>0]=1;Vb(e,0)}while(0);m=e+160|0;C=G+320|0;D=G+11680|0;E=1<0;p=e+(A+ -2<<2)+2612|0;F=G+284|0;J=0;do{if((c[z>>2]|0)==1){M=(J<>2]|0)){if(!(a[l>>0]|0))break;M=c[m>>2]|0;G=c[M+36>>2]|0;H=c[r>>2]|0;I=$(g>>c[H+13184>>2],G)|0;I=(c[M+4>>2]|0)+(I+(f>>c[H+13172>>2]<>2]))|0;if(B){J=0;do{b[D+(J<<1)>>1]=($(b[C+(J<<1)>>1]|0,c[F>>2]|0)|0)>>>3;J=J+1|0}while((J|0)!=(E|0));J=E}else J=0;Ma[c[p>>2]&7](I,D,G,c[H+52>>2]|0)}else zb(e,f,(J<>2]|0)+4>>2]|0)==2?2:1)|0));if(!(a[l>>0]|0))I=0;else{Vb(e,1);I=0}do{if((c[z>>2]|0)==1){M=(I<>2]|0)){if(!(a[l>>0]|0))break;M=c[m>>2]|0;G=c[M+40>>2]|0;w=c[r>>2]|0;H=$(g>>c[w+13188>>2],G)|0;H=(c[M+8>>2]|0)+(H+(f>>c[w+13176>>2]<>2]))|0;if(B){I=0;do{b[D+(I<<1)>>1]=($(b[C+(I<<1)>>1]|0,c[F>>2]|0)|0)>>>3;I=I+1|0}while((I|0)!=(E|0));I=E}else I=0;Ma[c[p>>2]&7](H,D,G,c[w+52>>2]|0)}else zb(e,f,(I<>2]|0)+4>>2]|0)==2?2:1)|0))}}while(0);if((o|0)!=0?(u=1<0):0){t=e+4344|0;r=0;do{w=$(r+g>>q,x)|0;o=0;do{a[(c[t>>2]|0)+((o+f>>q)+w)>>0]=1;o=o+y|0}while((o|0)<(u|0));r=r+y|0}while((r|0)<(u|0))}if(((a[e+2061>>0]|0)==0?(Cb(e,f,g,n),(a[(c[e+204>>2]|0)+40>>0]|0)!=0):0)?(a[v+31256>>0]|0)!=0:0)Tb(e,f,g,n)}else{u=n+ -1|0;n=1<>2]|0;f=xb(a,b)|0;if(!f){c[e+284>>2]=0;i=d;return}else{c[e+284>>2]=1-((yb(a,b)|0)<<1)<>2]|0;s=c[d+200>>2]|0;q=c[s+52>>2]|0;V=c[s+(j<<2)+13168>>2]|0;U=c[s+(j<<2)+13180>>2]|0;k=1<>2]|0;oa=k<>2]|0;W=f>>X&_;ia=g>>X&_;Y=_+2|0;aa=($(ia,Y)|0)+W|0;ba=c[d+204>>2]|0;ca=c[ba+1684>>2]|0;aa=c[ca+(aa<<2)>>2]|0;n=c[d+160>>2]|0;d=(c[n+(j<<2)+32>>2]|0)>>>1;n=c[n+(j<<2)>>2]|0;m=($(d,g>>U)|0)+(f>>V)|0;o=n+(m<<1)|0;p=(j|0)==0;r=c[(p?t+288|0:t+292|0)>>2]|0;w=v+2|0;B=y+2|0;z=A+2|0;u=x+2|0;if(!(c[t+31288>>2]|0))na=0;else na=(aa|0)>(c[ca+(W+ -1+($(_&ia+(oa>>X),Y)|0)<<2)>>2]|0);la=na&1;da=c[t+31292>>2]|0;M=c[t+31300>>2]|0;Z=c[t+31296>>2]|0;if(!(c[t+31304>>2]|0))ja=0;else ja=(aa|0)>(c[ca+(($(Y,ia+ -1|0)|0)+(_&W+(ma>>X))<<2)>>2]|0);W=ja&1;ca=(oa<<1)+g|0;_=s+13124|0;ia=c[_>>2]|0;X=oa+g|0;ca=((ca|0)>(ia|0)?ia:ca)-X>>U;ia=(ma<<1)+f|0;aa=s+13120|0;ra=c[aa>>2]|0;Y=ma+f|0;ia=((ia|0)>(ra|0)?ra:ia)-Y>>V;ba=ba+20|0;if((a[ba>>0]|0)==1){ka=c[s+13084>>2]|0;pa=oa>>ka;ma=ma>>ka;qa=(1<>2]|0)-(X>>ka)|0;na=(pa|0)>(na|0)?na:pa;if((na|0)>0){la=0;ra=0;do{la=la|1;ra=ra+2|0}while((ra|0)<(na|0))}else la=0}if(!((da|0)!=1|qa)){ra=(c[s+13160>>2]|0)-(g>>ka)|0;pa=(pa|0)>(ra|0)?ra:pa;if((pa|0)>0){da=0;na=0;do{da=da|1;na=na+2|0}while((na|0)<(pa|0))}else da=0}na=(oa|0)!=0;if(!((Z|0)!=1|na)){oa=(c[s+13156>>2]|0)-(f>>ka)|0;oa=(ma|0)>(oa|0)?oa:ma;if((oa|0)>0){Z=0;pa=0;do{Z=Z|1;pa=pa+2|0}while((pa|0)<(oa|0))}else Z=0}if(!(na|ja^1)){ka=(c[s+13156>>2]|0)-(Y>>ka)|0;ka=(ma|0)>(ka|0)?ka:ma;if((ka|0)>0){W=0;ja=0;do{W=W|1;ja=ja+2|0}while((ja|0)<(ka|0))}else W=0}ka=w+0|0;ja=ka+128|0;do{b[ka>>1]=32896;ka=ka+2|0}while((ka|0)<(ja|0));ka=B+0|0;ja=ka+128|0;do{b[ka>>1]=32896;ka=ka+2|0}while((ka|0)<(ja|0));b[y>>1]=128;ma=W}else ma=W;ka=(M|0)!=0;if(ka){ra=b[n+(m+~d<<1)>>1]|0;b[v>>1]=ra;b[y>>1]=ra}ja=(Z|0)!=0;if(ja)ce(B|0,n+(m-d<<1)|0,k<<1|0)|0;W=(ma|0)!=0;if(W?(ha=k+1|0,ce(y+(ha<<1)|0,n+(k-d+m<<1)|0,k<<1|0)|0,fa=he(e[n+(k+ -1-d+m+ia<<1)>>1]|0,0,65537,65537)|0,ga=D,ea=k-ia|0,(ea|0)>0):0){ia=ia+ha|0;ha=0;do{ra=y+(ia+ha<<1)|0;qa=ra;b[qa>>1]=fa;b[qa+2>>1]=fa>>>16;ra=ra+4|0;b[ra>>1]=ga;b[ra+2>>1]=ga>>>16;ha=ha+4|0}while((ha|0)<(ea|0))}ea=(da|0)!=0;if(ea&(k|0)>0){fa=m+ -1|0;ga=0;do{ra=ga;ga=ga+1|0;b[v+(ga<<1)>>1]=b[n+(fa+($(ra,d)|0)<<1)>>1]|0}while((ga|0)!=(k|0))}fa=(la|0)!=0;if(fa){ia=ca+k|0;ha=m+ -1|0;if((ca|0)>0){ga=k;do{ra=ga;ga=ga+1|0;b[v+(ga<<1)>>1]=b[n+(ha+($(ra,d)|0)<<1)>>1]|0}while((ga|0)<(ia|0))}ia=he(e[n+(ha+($(ia+ -1|0,d)|0)<<1)>>1]|0,0,65537,65537)|0;ha=D;ga=k-ca|0;if((ga|0)>0){ca=k+1+ca|0;na=0;do{ra=v+(ca+na<<1)|0;qa=ra;b[qa>>1]=ia;b[qa+2>>1]=ia>>>16;ra=ra+4|0;b[ra>>1]=ha;b[ra+2>>1]=ha>>>16;na=na+4|0}while((na|0)<(ga|0))}}do if((a[ba>>0]|0)==1?(ra=la|da,S=(ra|0)==0,ra=ra|M,T=(ra|0)==0,(Z|ma|ra|0)!=0):0){ba=k<<1;ca=c[aa>>2]|0;if(((ba<>V;_=c[_>>2]|0;if(((ba<=(_|0))ba=_-g>>U;if(!W)if((Y|0)<(ca|0))V=k;else V=ca-f>>V;else V=aa;if(!fa)if((X|0)<(_|0))U=k;else U=_-g>>U;else U=ba;X=b[y>>1]|0;if(T)b[v>>1]=X;b[v>>1]=X;if(!S){S=0;while(1)if((S|0)<(U|0))S=S+4|0;else break}if(!ea?(R=he(X&65535|0,0,65537,65537)|0,Q=D,(k|0)>0):0){S=0;do{ra=v+((S|1)<<1)|0;qa=ra;b[qa>>1]=R;b[qa+2>>1]=R>>>16;ra=ra+4|0;b[ra>>1]=Q;b[ra+2>>1]=Q>>>16;S=S+4|0}while((S|0)<(k|0))}do if(!fa){Q=he(e[v+(k<<1)>>1]|0,0,65537,65537)|0;S=D;if((k|0)<=0)break;T=k+1|0;R=0;do{ra=v+(T+R<<1)|0;qa=ra;b[qa>>1]=Q;b[qa+2>>1]=Q>>>16;ra=ra+4|0;b[ra>>1]=S;b[ra+2>>1]=S>>>16;R=R+4|0}while((R|0)<(k|0))}while(0);g=(g|0)==0;if((f|0)==0&(U|0)>0){f=0;do{ra=v+((f|1)<<1)|0;qa=ra;b[qa>>1]=0;b[qa+2>>1]=0>>>16;ra=ra+4|0;b[ra>>1]=0;b[ra+2>>1]=0>>>16;f=f+4|0}while((f|0)<(U|0))}b[y>>1]=b[v>>1]|0;if(g)break;else f=0;while(1)if((f|0)<(V|0))f=f+4|0;else break}while(0);a:do if(!fa){if(ea){P=he(e[v+(k<<1)>>1]|0,0,65537,65537)|0;f=D;if((k|0)<=0){P=84;break}g=k+1|0;Q=0;while(1){ra=v+(g+Q<<1)|0;qa=ra;b[qa>>1]=P;b[qa+2>>1]=P>>>16;ra=ra+4|0;b[ra>>1]=f;b[ra+2>>1]=f>>>16;Q=Q+4|0;if((Q|0)>=(k|0)){P=84;break a}}}if(ka){f=he(e[v>>1]|0,0,65537,65537)|0;P=D;O=k<<1;if((k|0)>0)N=0;else{P=87;break}while(1){ra=v+((N|1)<<1)|0;qa=ra;b[qa>>1]=f;b[qa+2>>1]=f>>>16;ra=ra+4|0;b[ra>>1]=P;b[ra+2>>1]=P>>>16;N=N+4|0;if((N|0)>=(O|0)){P=87;break a}}}if(ja){N=b[B>>1]|0;b[v>>1]=N;N=he(N&65535|0,0,65537,65537)|0;O=D;M=k<<1;if((k|0)>0)P=0;else{P=89;break}while(1){ra=v+((P|1)<<1)|0;qa=ra;b[qa>>1]=N;b[qa+2>>1]=N>>>16;ra=ra+4|0;b[ra>>1]=O;b[ra+2>>1]=O>>>16;P=P+4|0;if((P|0)>=(M|0)){P=89;break a}}}if(!W){g=1<>1]=g;R=he(g&65535|0,0,65537,65537)|0;Q=D;P=k<<1;f=(k|0)>0;if(f)S=0;else{P=84;break}do{ra=y+((S|1)<<1)|0;qa=ra;b[qa>>1]=R;b[qa+2>>1]=R>>>16;ra=ra+4|0;b[ra>>1]=Q;b[ra+2>>1]=Q>>>16;S=S+4|0}while((S|0)<(P|0));g=he(g&65535|0,0,65537,65537)|0;Q=D;if(f)f=0;else{P=84;break}while(1){ra=v+((f|1)<<1)|0;qa=ra;b[qa>>1]=g;b[qa+2>>1]=g>>>16;ra=ra+4|0;b[ra>>1]=Q;b[ra+2>>1]=Q>>>16;f=f+4|0;if((f|0)>=(P|0)){P=84;break a}}}M=y+(k+1<<1)|0;O=b[M>>1]|0;N=he(O&65535|0,0,65537,65537)|0;L=D;K=(k|0)>0;if(K)O=0;else{b[v>>1]=O;break}do{ra=y+((O|1)<<1)|0;qa=ra;b[qa>>1]=N;b[qa+2>>1]=N>>>16;ra=ra+4|0;b[ra>>1]=L;b[ra+2>>1]=L>>>16;O=O+4|0}while((O|0)<(k|0));M=b[M>>1]|0;b[v>>1]=M;M=he(M&65535|0,0,65537,65537)|0;L=D;N=k<<1;if(K){K=0;do{ra=v+((K|1)<<1)|0;qa=ra;b[qa>>1]=M;b[qa+2>>1]=M>>>16;ra=ra+4|0;b[ra>>1]=L;b[ra+2>>1]=L>>>16;K=K+4|0}while((K|0)<(N|0));P=92}else P=92}else P=84;while(0);if((P|0)==84)if((da|0)==0?(N=he(e[v+(k+1<<1)>>1]|0,0,65537,65537)|0,O=D,(k|0)>0):0){P=0;do{ra=v+((P|1)<<1)|0;qa=ra;b[qa>>1]=N;b[qa+2>>1]=N>>>16;ra=ra+4|0;b[ra>>1]=O;b[ra+2>>1]=O>>>16;P=P+4|0}while((P|0)<(k|0));P=87}else P=87;if((P|0)==87)if(!M){b[v>>1]=b[w>>1]|0;P=89}else P=89;if((P|0)==89)if((Z|0)==0?(K=he(e[v>>1]|0,0,65537,65537)|0,L=D,(k|0)>0):0){M=0;do{ra=y+((M|1)<<1)|0;qa=ra;b[qa>>1]=K;b[qa+2>>1]=K>>>16;ra=ra+4|0;b[ra>>1]=L;b[ra+2>>1]=L>>>16;M=M+4|0}while((M|0)<(k|0));P=92}else P=92;if(((P|0)==92?!W:0)?(J=he(e[y+(k<<1)>>1]|0,0,65537,65537)|0,I=D,(k|0)>0):0){K=k+1|0;L=0;do{ra=y+(K+L<<1)|0;qa=ra;b[qa>>1]=J;b[qa+2>>1]=J>>>16;ra=ra+4|0;b[ra>>1]=I;b[ra+2>>1]=I>>>16;L=L+4|0}while((L|0)<(k|0))}I=b[v>>1]|0;b[y>>1]=I;b:do if(!(c[s+13112>>2]|0)){if(p){if((r|0)==1|(k|0)==4){u=B;break}}else if(((r|0)==1?1:(c[s+4>>2]|0)!=3)|(k|0)==4){u=B;break}ra=r+ -26|0;ra=(ra|0)>-1?ra:26-r|0;qa=r+ -10|0;qa=(qa|0)>-1?qa:10-r|0;if((((ra|0)>(qa|0)?qa:ra)|0)>(c[1576+(h+ -3<<2)>>2]|0)){J=1<>0]|0)!=0&(h|0)==5?(G=I&65535,H=b[y+128>>1]|0,F=H&65535,ra=F+G-(e[y+64>>1]<<1)|0,(((ra|0)>-1?ra:0-ra|0)|0)<(J|0)):0)?(C=v+128|0,E=b[C>>1]|0,ra=(E&65535)+G-(e[v+64>>1]<<1)|0,(((ra|0)>-1?ra:0-ra|0)|0)<(J|0)):0){b[x>>1]=I;b[x+128>>1]=H;y=0;do{ra=y;y=y+1|0;b[x+(y<<1)>>1]=(($(G,63-ra|0)|0)+32+($(F,y)|0)|0)>>>6}while((y|0)!=63);y=0;while(1){x=y+1|0;b[v+(x<<1)>>1]=(($(I&65535,63-y|0)|0)+32+($(E&65535,x)|0)|0)>>>6;if((x|0)==63)break b;I=b[v>>1]|0;E=b[C>>1]|0;y=x}}C=k<<1;H=b[v+(C<<1)>>1]|0;b[A+(C<<1)>>1]=H;F=b[y+(C<<1)>>1]|0;b[x+(C<<1)>>1]=F;C=C+ -2|0;E=(C|0)>-1;if(E){G=C;while(1){ra=G+1|0;qa=H;H=b[v+(ra<<1)>>1]|0;b[A+(ra<<1)>>1]=((qa&65535)+2+((H&65535)<<1)+(e[v+(G<<1)>>1]|0)|0)>>>2;if((G|0)<=0)break;else G=G+ -1|0}}ra=((e[w>>1]|0)+2+((I&65535)<<1)+(e[B>>1]|0)|0)>>>2&65535;b[A>>1]=ra;b[x>>1]=ra;if(E)while(1){ra=C+1|0;qa=F;F=b[y+(ra<<1)>>1]|0;b[x+(ra<<1)>>1]=((qa&65535)+2+((F&65535)<<1)+(e[y+(C<<1)>>1]|0)|0)>>>2;if((C|0)<=0){w=z;break}else C=C+ -1|0}else w=z}else u=B}else u=B;while(0);if(!r){Xb(o,u,w,d,h);i=l;return}else if((r|0)==1){if((k|0)>0){j=k;q=0;do{j=(e[w+(q<<1)>>1]|0)+j+(e[u+(q<<1)>>1]|0)|0;q=q+1|0}while((q|0)!=(k|0));r=j>>h+1;s=he(r|0,((r|0)<0)<<31>>31|0,65537,65537)|0;t=D;q=0;do{j=($(q,d)|0)+m|0;h=0;do{ra=n+(j+h<<1)|0;qa=ra;a[qa>>0]=s;a[qa+1>>0]=s>>8;a[qa+2>>0]=s>>16;a[qa+3>>0]=s>>24;ra=ra+4|0;a[ra>>0]=t;a[ra+1>>0]=t>>8;a[ra+2>>0]=t>>16;a[ra+3>>0]=t>>24;h=h+4|0}while((h|0)<(k|0));q=q+1|0}while((q|0)!=(k|0))}else r=k>>h+1;if(!(p&(k|0)<32)){i=l;return}b[o>>1]=((r<<1)+2+(e[w>>1]|0)+(e[u>>1]|0)|0)>>>2;if((k|0)<=1){i=l;return}o=(r*3|0)+2|0;p=1;do{b[n+(p+m<<1)>>1]=((e[u+(p<<1)>>1]|0)+o|0)>>>2;p=p+1|0}while((p|0)!=(k|0));p=1;do{b[n+(($(p,d)|0)+m<<1)>>1]=((e[w+(p<<1)>>1]|0)+o|0)>>>2;p=p+1|0}while((p|0)!=(k|0));i=l;return}else{if(!(c[s+13104>>2]|0))m=0;else m=(a[t+31256>>0]|0)!=0;Yb(o,u,w,d,j,r,k,m&1,q);i=l;return}}function Xb(a,c,d,f,g){a=a|0;c=c|0;d=d|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;m=i;j=1<>1]|0,l-r|0)|0;s=r;r=r+1|0;u=$(e[h>>1]|0,r)|0;t=$(e[c+(s<<1)>>1]|0,p)|0;b[a+(s+q<<1)>>1]=v+j+u+t+($(e[k>>1]|0,n)|0)>>g}while((r|0)!=(j|0))}while((n|0)!=(j|0));i=m;return}function Yb(c,f,g,h,j,k,l,m,n){c=c|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;o=i;i=i+208|0;r=o;p=a[1592+(k+ -2)>>0]|0;q=r+(l<<1)|0;s=($(p,l)|0)>>5;if((k|0)>17){u=f+ -2|0;t=k+ -11|0;if(t>>>0<15&(s|0)<-1){if((l|0)>=0){u=0;do{w=f+(u+ -1<<1)|0;y=w;y=d[y>>0]|d[y+1>>0]<<8|d[y+2>>0]<<16|d[y+3>>0]<<24;w=w+4|0;w=d[w>>0]|d[w+1>>0]<<8|d[w+2>>0]<<16|d[w+3>>0]<<24;x=r+(u+l<<1)|0;v=x;b[v>>1]=y;b[v+2>>1]=y>>>16;x=x+4|0;b[x>>1]=w;b[x+2>>1]=w>>>16;u=u+4|0}while((u|0)<=(l|0))}if((s|0)<0){t=b[1632+(t<<1)>>1]|0;do{b[r+(s+l<<1)>>1]=b[g+((($(t,s)|0)+128>>8)+ -1<<1)>>1]|0;s=s+1|0}while((s|0)!=0)}}else q=u;r=(l|0)>0;if(r){s=0;do{w=s;s=s+1|0;v=$(s,p)|0;t=v>>5;v=v&31;if(!v){t=t+1|0;v=$(w,h)|0;u=0;do{x=q+(t+u<<1)|0;z=x;z=d[z>>0]|d[z+1>>0]<<8|d[z+2>>0]<<16|d[z+3>>0]<<24;x=x+4|0;x=d[x>>0]|d[x+1>>0]<<8|d[x+2>>0]<<16|d[x+3>>0]<<24;y=c+(u+v<<1)|0;w=y;a[w>>0]=z;a[w+1>>0]=z>>8;a[w+2>>0]=z>>16;a[w+3>>0]=z>>24;y=y+4|0;a[y>>0]=x;a[y+1>>0]=x>>8;a[y+2>>0]=x>>16;a[y+3>>0]=x>>24;u=u+4|0}while((u|0)<(l|0))}else{u=32-v|0;w=$(w,h)|0;x=0;do{z=x+t|0;y=$(e[q+(z+1<<1)>>1]|0,u)|0;b[c+(x+w<<1)>>1]=(y+16+($(e[q+(z+2<<1)>>1]|0,v)|0)|0)>>>5;z=x|1;y=z+t|0;A=$(e[q+(y+1<<1)>>1]|0,u)|0;b[c+(z+w<<1)>>1]=(A+16+($(e[q+(y+2<<1)>>1]|0,v)|0)|0)>>>5;z=x|2;y=z+t|0;A=$(e[q+(y+1<<1)>>1]|0,u)|0;b[c+(z+w<<1)>>1]=(A+16+($(e[q+(y+2<<1)>>1]|0,v)|0)|0)>>>5;z=x|3;y=z+t|0;A=$(e[q+(y+1<<1)>>1]|0,u)|0;b[c+(z+w<<1)>>1]=(A+16+($(e[q+(y+2<<1)>>1]|0,v)|0)|0)>>>5;x=x+4|0}while((x|0)<(l|0))}}while((s|0)!=(l|0))}if(!((k|0)==26&(j|0)==0&(l|0)<32&(m|0)==0&r)){i=o;return}j=g+ -2|0;k=1<>1]|0)-(e[j>>1]|0)>>1)+(e[f>>1]|0)|0;if(p&m)p=0-p>>31&k;b[c+(($(n,h)|0)<<1)>>1]=p;n=n+1|0}while((n|0)!=(l|0));i=o;return}u=g+ -2|0;t=k+ -11|0;if(t>>>0<15&(s|0)<-1){if((l|0)>=0){u=0;do{z=g+(u+ -1<<1)|0;x=z;x=d[x>>0]|d[x+1>>0]<<8|d[x+2>>0]<<16|d[x+3>>0]<<24;z=z+4|0;z=d[z>>0]|d[z+1>>0]<<8|d[z+2>>0]<<16|d[z+3>>0]<<24;A=r+(u+l<<1)|0;y=A;b[y>>1]=x;b[y+2>>1]=x>>>16;A=A+4|0;b[A>>1]=z;b[A+2>>1]=z>>>16;u=u+4|0}while((u|0)<=(l|0))}if((s|0)<0){t=b[1632+(t<<1)>>1]|0;do{b[r+(s+l<<1)>>1]=b[f+((($(t,s)|0)+128>>8)+ -1<<1)>>1]|0;s=s+1|0}while((s|0)!=0)}}else q=u;r=(l|0)>0;if(r){t=0;do{s=t;t=t+1|0;w=$(t,p)|0;x=w>>5;w=w&31;if(!w){v=x+1|0;u=0;do{b[c+(($(u,h)|0)+s<<1)>>1]=b[q+(v+u<<1)>>1]|0;u=u+1|0}while((u|0)!=(l|0))}else{v=32-w|0;u=0;do{A=u+x|0;z=$(e[q+(A+1<<1)>>1]|0,v)|0;b[c+(($(u,h)|0)+s<<1)>>1]=(z+16+($(e[q+(A+2<<1)>>1]|0,w)|0)|0)>>>5;u=u+1|0}while((u|0)!=(l|0))}}while((t|0)!=(l|0))}if(!((k|0)==10&(j|0)==0&(l|0)<32&(m|0)==0&r)){i=o;return}h=f+ -2|0;j=1<>1]|0)-(e[h>>1]|0)>>1)+(e[g>>1]|0)|0;if(m&n)m=0-m>>31&j;b[c+(k<<1)>>1]=m;m=k|1;p=((e[f+(m<<1)>>1]|0)-(e[h>>1]|0)>>1)+(e[g>>1]|0)|0;if(p&n)p=0-p>>31&j;b[c+(m<<1)>>1]=p;m=k|2;p=((e[f+(m<<1)>>1]|0)-(e[h>>1]|0)>>1)+(e[g>>1]|0)|0;if(p&n)p=0-p>>31&j;b[c+(m<<1)>>1]=p;m=k|3;p=((e[f+(m<<1)>>1]|0)-(e[h>>1]|0)>>1)+(e[g>>1]|0)|0;if(p&n)p=0-p>>31&j;b[c+(m<<1)>>1]=p;k=k+4|0}while((k|0)<(l|0));i=o;return}function Zb(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0;g=i;h=c[e>>2]|0;if(!h){i=g;return}if(!(c[h+304>>2]|0)){i=g;return}h=e+46|0;f=(d[h>>0]|0)&(f^255)&255;a[h>>0]=f;if(f<<24>>24){i=g;return}Wc(c[b+4>>2]|0,e+4|0);c[e+24>>2]=0;i=g;return}function _b(a){a=a|0;var b=0;b=i;Zb(a,a+2524|0,6);i=b;return}function $b(a){a=a|0;var b=0;b=i;Zb(a,a+2524|0,-1);i=b;return}function ac(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;h=d+4364|0;if(((c[(c[d+2524>>2]|0)+304>>2]|0)!=0?(b[d+2568>>1]|0)==(b[h>>1]|0):0)?(c[d+2544>>2]|0)==(f|0):0){j=-1094995529;i=g;return j|0}j=d+2524|0;if(c[(c[j>>2]|0)+304>>2]|0){j=-12;i=g;return j|0}if((Vc(c[d+4>>2]|0,d+2528|0,1)|0)<0){j=-12;i=g;return j|0}k=d+200|0;m=c[k>>2]|0;c[d+2540>>2]=$(c[m+13132>>2]|0,c[m+13128>>2]|0)|0;m=d+4520|0;l=c[j>>2]|0;c[l+244>>2]=(c[m>>2]|0)==1&1;c[l+240>>2]=((c[m>>2]|0)+ -1|0)>>>0<2&1;c[e>>2]=l;c[d+2520>>2]=j;a[d+2570>>0]=(a[d+1450>>0]|0)==0?2:3;c[d+2544>>2]=f;b[d+2568>>1]=b[h>>1]|0;j=d+2552|0;f=(c[k>>2]|0)+20|0;c[j+0>>2]=c[f+0>>2];c[j+4>>2]=c[f+4>>2];c[j+8>>2]=c[f+8>>2];c[j+12>>2]=c[f+12>>2];j=0;i=g;return j|0}function bc(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;l=d+2046|0;k=d+2572|0;h=d+4366|0;n=(f|0)==0;m=d+4364|0;f=d+200|0;while(1){if((a[l>>0]|0)==1){p=d+2524|0;o=d+2570|0;if(((a[o>>0]&8)==0?(c[d+2544>>2]|0)!=(c[k>>2]|0):0)?(b[d+2568>>1]|0)==(b[h>>1]|0):0)Zb(d,p,1)}else o=d+2570|0;if(!(a[o>>0]&1))o=0;else o=(b[d+2568>>1]|0)==(b[h>>1]|0)&1;if(((n?(b[h>>1]|0)==(b[m>>1]|0):0)?(j=c[f>>2]|0,(j|0)!=0):0)?(o|0)<=(c[j+(((c[j+72>>2]|0)+ -1|0)*12|0)+80>>2]|0):0){d=0;h=21;break}if(o){h=15;break}o=b[h>>1]|0;if(o<<16>>16==(b[m>>1]|0)){d=0;h=21;break}b[h>>1]=(o&65535)+1&255}if((h|0)==15){h=d+2524|0;e=Bd(e,c[h>>2]|0)|0;if(!(a[d+2570>>0]&8))Zb(d,h,1);else Zb(d,h,9);p=(e|0)<0?e:1;i=g;return p|0}else if((h|0)==21){i=g;return d|0}return 0}function cc(){var b=0,c=0,d=0,e=0,f=0;b=i;if(!(a[1664]|0))c=0;else{i=b;return}do{d=0;do{f=($(d<<1|1,c)|0)&127;e=f>>>0>63;f=e?f+ -64|0:f;e=e?-1:1;if((f|0)>31){f=64-f|0;e=0-e|0}a[1664+(c<<5)+d>>0]=$(a[2688+f>>0]|0,e)|0;d=d+1|0}while((d|0)!=32);c=c+1|0}while((c|0)!=32);i=b;return}function dc(a,b){a=a|0;b=b|0;c[a>>2]=4;c[a+4>>2]=1;c[a+8>>2]=2;c[a+12>>2]=3;c[a+16>>2]=4;c[a+20>>2]=1;c[a+24>>2]=2;c[a+28>>2]=1;c[a+32>>2]=3;c[a+36>>2]=4;c[a+40>>2]=5;c[a+44>>2]=6;c[a+48>>2]=2;c[a+52>>2]=3;c[a+56>>2]=4;c[a+60>>2]=5;c[a+64>>2]=1;c[a+68>>2]=1;c[a+72>>2]=2;c[a+1676>>2]=5;c[a+1680>>2]=6;c[a+1684>>2]=1;c[a+1688>>2]=2;c[a+1692>>2]=5;c[a+1696>>2]=6;c[a+1700>>2]=1;c[a+1704>>2]=2;return}function ec(a,c,d,e,f,g,h){a=a|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0;j=i;c=c>>>1;if((e|0)<=0){i=j;return}k=(d|0)>0;h=h-g|0;l=0;while(1){if(k){m=0;do{b[a+(m<<1)>>1]=(ad(f,g)|0)<>>1;f=1<>1]|0)+(e[k>>1]|0)|0;if(n&h)n=0-n>>31&f;b[k>>1]=n;m=m+1|0;if((m|0)==4)break;else l=l+2|0}j=j+1|0;if((j|0)==4)break;else{c=c+8|0;a=a+(d<<1)|0}}i=g;return}function gc(a,c,d,f){a=a|0;c=c|0;d=d|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;d=d>>>1;f=1<>1]|0)+(e[k>>1]|0)|0;if(n&h)n=0-n>>31&f;b[k>>1]=n;m=m+1|0;if((m|0)==8)break;else l=l+2|0}j=j+1|0;if((j|0)==8)break;else{c=c+16|0;a=a+(d<<1)|0}}i=g;return} + + + +function hc(a,c,d,f){a=a|0;c=c|0;d=d|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;d=d>>>1;f=1<>1]|0)+(e[k>>1]|0)|0;if(n&h)n=0-n>>31&f;b[k>>1]=n;m=m+1|0;if((m|0)==16)break;else l=l+2|0}j=j+1|0;if((j|0)==16)break;else{c=c+32|0;a=a+(d<<1)|0}}i=g;return}function ic(a,c,d,f){a=a|0;c=c|0;d=d|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;d=d>>>1;f=1<>1]|0)+(e[k>>1]|0)|0;if(n&h)n=0-n>>31&f;b[k>>1]=n;m=m+1|0;if((m|0)==32)break;else l=l+2|0}j=j+1|0;if((j|0)==32)break;else{c=c+64|0;a=a+(d<<1)|0}}i=g;return}function jc(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;c=c<<16>>16;d=15-d-c|0;c=1<0){f=1<0){h=a;a=0}else{i=e;return}while(1){j=h;g=0;while(1){b[j>>1]=(b[j>>1]|0)+f>>d;g=g+1|0;if((g|0)==(c|0))break;else j=j+2|0}a=a+1|0;if((a|0)==(c|0))break;else h=h+(c<<1)|0}i=e;return}if((c|0)<=0){i=e;return}d=0-d|0;f=0;while(1){g=a;h=0;while(1){b[g>>1]=b[g>>1]<>16);if(d){d=c+ -1|0;if((d|0)<=0){i=f;return}g=(c|0)>0;h=0;do{if(g){j=0;do{k=a+(j+c<<1)|0;b[k>>1]=(e[k>>1]|0)+(e[a+(j<<1)>>1]|0);j=j+1|0}while((j|0)!=(c|0))}a=a+(c<<1)|0;h=h+1|0}while((h|0)!=(d|0));i=f;return}if((c|0)<=0){i=f;return}d=(c|0)>1;h=0;while(1){if(d){j=b[a>>1]|0;g=1;do{k=a+(g<<1)|0;j=(e[k>>1]|0)+(j&65535)&65535;b[k>>1]=j;g=g+1|0}while((g|0)!=(c|0))}h=h+1|0;if((h|0)==(c|0))break;else a=a+(c<<1)|0}i=f;return}function lc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;d=i;e=0;g=a;while(1){q=b[g>>1]|0;n=g+16|0;o=b[n>>1]|0;h=o+q|0;f=g+24|0;p=b[f>>1]|0;m=p+o|0;j=q-p|0;l=g+8|0;k=(b[l>>1]|0)*74|0;p=((q-o+p|0)*74|0)+64|0;o=p>>7;if((o+32768|0)>>>0>65535)o=p>>31^32767;b[n>>1]=o;o=(h*29|0)+64+(m*55|0)+k|0;n=o>>7;if((n+32768|0)>>>0>65535)n=o>>31^32767;b[g>>1]=n;m=($(m,-29)|0)+64+(j*55|0)+k|0;n=m>>7;if((n+32768|0)>>>0>65535)n=m>>31^32767;b[l>>1]=n;j=(h*55|0)+64+(j*29|0)-k|0;h=j>>7;if((h+32768|0)>>>0>65535)h=j>>31^32767;b[f>>1]=h;e=e+1|0;if((e|0)==4)break;else g=g+2|0}e=20-c|0;c=1<>1]|0;n=a+4|0;q=b[n>>1]|0;l=q+p|0;f=a+6|0;o=b[f>>1]|0;m=o+q|0;h=p-o|0;k=a+2|0;j=(b[k>>1]|0)*74|0;o=((p-q+o|0)*74|0)+c>>e;if((o+32768|0)>>>0>65535)o=o>>31^32767;b[n>>1]=o;n=(l*29|0)+c+(m*55|0)+j>>e;if((n+32768|0)>>>0>65535)n=n>>31^32767;b[a>>1]=n;m=($(m,-29)|0)+c+(h*55|0)+j>>e;if((m+32768|0)>>>0>65535)m=m>>31^32767;b[k>>1]=m;h=(l*55|0)+c+(h*29|0)-j>>e;if((h+32768|0)>>>0>65535)h=h>>31^32767;b[f>>1]=h;g=g+1|0;if((g|0)==4)break;else a=a+8|0}i=d;return}function mc(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;c=i;e=0;g=a;while(1){n=b[g>>1]<<6;k=g+16|0;m=b[k>>1]<<6;j=m+n|0;m=n-m|0;n=g+8|0;l=b[n>>1]|0;f=g+24|0;o=b[f>>1]|0;h=(o*36|0)+(l*83|0)|0;l=($(o,-83)|0)+(l*36|0)|0;o=j+64+h|0;p=o>>7;if((p+32768|0)>>>0>65535)p=o>>31^32767;b[g>>1]=p;p=m+64+l|0;o=p>>7;if((o+32768|0)>>>0>65535)o=p>>31^32767;b[n>>1]=o;l=m-l+64|0;m=l>>7;if((m+32768|0)>>>0>65535)m=l>>31^32767;b[k>>1]=m;j=j-h+64|0;h=j>>7;if((h+32768|0)>>>0>65535)h=j>>31^32767;b[f>>1]=h;e=e+1|0;if((e|0)==4)break;else g=g+2|0}e=20-d|0;d=1<>1]<<6;k=a+4|0;o=b[k>>1]<<6;m=a+2|0;l=b[m>>1]|0;f=a+6|0;j=b[f>>1]|0;h=(j*36|0)+(l*83|0)|0;l=($(j,-83)|0)+(l*36|0)|0;j=o+n+d|0;p=j+h>>e;if((p+32768|0)>>>0>65535)p=p>>31^32767;b[a>>1]=p;n=n-o+d|0;o=n+l>>e;if((o+32768|0)>>>0>65535)o=o>>31^32767;b[m>>1]=o;l=n-l>>e;if((l+32768|0)>>>0>65535)l=l>>31^32767;b[k>>1]=l;h=j-h>>e;if((h+32768|0)>>>0>65535)h=h>>31^32767;b[f>>1]=h;g=g+1|0;if((g|0)==4)break;else a=a+8|0}i=c;return}function nc(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;j=i;i=i+64|0;r=j+48|0;p=j+32|0;g=j+16|0;h=j;q=(e|0)>8;s=e+4|0;k=r+4|0;l=r+8|0;m=r+12|0;o=0;s=(s|0)>8?8:s;n=d;while(1){c[p+0>>2]=0;c[p+4>>2]=0;c[p+8>>2]=0;c[p+12>>2]=0;w=(s|0)>1;t=0;do{if(w){v=p+(t<<2)|0;u=c[v>>2]|0;x=1;do{u=($(b[n+(x<<3<<1)>>1]|0,a[1664+(x<<2<<5)+t>>0]|0)|0)+u|0;x=x+2|0}while((x|0)<(s|0));c[v>>2]=u}t=t+1|0}while((t|0)!=4);w=b[n>>1]<<6;v=b[n+64>>1]<<6;x=v+w|0;v=w-v|0;w=b[n+32>>1]|0;u=b[n+96>>1]|0;t=(u*36|0)+(w*83|0)|0;w=($(u,-83)|0)+(w*36|0)|0;u=t+x|0;c[r>>2]=u;c[k>>2]=w+v;c[l>>2]=v-w;c[m>>2]=x-t;t=0;while(1){v=c[p+(t<<2)>>2]|0;w=u+64+v|0;x=w>>7;if((x+32768|0)>>>0>65535)x=w>>31^32767;b[n+(t<<3<<1)>>1]=x;v=u-v+64|0;u=v>>7;if((u+32768|0)>>>0>65535)u=v>>31^32767;b[n+(7-t<<3<<1)>>1]=u;t=t+1|0;if((t|0)==4)break;u=c[r+(t<<2)>>2]|0}if((s|0)<8)s=(o&3|0)==0&(o|0)!=0?s+ -4|0:s;o=o+1|0;if((o|0)==8)break;else n=n+2|0}k=q?8:e;l=20-f|0;m=1<1;n=g+4|0;o=g+8|0;e=g+12|0;p=0;while(1){c[h+0>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;t=0;do{if(f){q=h+(t<<2)|0;s=c[q>>2]|0;r=1;do{s=($(b[d+(r<<1)>>1]|0,a[1664+(r<<2<<5)+t>>0]|0)|0)+s|0;r=r+2|0}while((r|0)<(k|0));c[q>>2]=s}t=t+1|0}while((t|0)!=4);w=b[d>>1]<<6;v=b[d+8>>1]<<6;x=v+w|0;v=w-v|0;w=b[d+4>>1]|0;s=b[d+12>>1]|0;q=(s*36|0)+(w*83|0)|0;w=($(s,-83)|0)+(w*36|0)|0;s=q+x|0;c[g>>2]=s;c[n>>2]=w+v;c[o>>2]=v-w;c[e>>2]=x-q;q=0;while(1){r=c[h+(q<<2)>>2]|0;s=s+m|0;t=s+r>>l;if((t+32768|0)>>>0>65535)t=t>>31^32767;b[d+(q<<1)>>1]=t;r=s-r>>l;if((r+32768|0)>>>0>65535)r=r>>31^32767;b[d+(7-q<<1)>>1]=r;q=q+1|0;if((q|0)==4)break;s=c[g+(q<<2)>>2]|0}p=p+1|0;if((p|0)==8)break;else d=d+16|0}i=j;return}function oc(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;g=i;i=i+192|0;t=g+160|0;u=g+128|0;v=g+112|0;s=g+96|0;j=g+64|0;l=g+32|0;h=g+16|0;k=g;m=(e|0)>16;w=e+4|0;n=v+4|0;o=v+8|0;p=v+12|0;r=0;w=(w|0)>16?16:w;q=d;while(1){c[u+0>>2]=0;c[u+4>>2]=0;c[u+8>>2]=0;c[u+12>>2]=0;c[u+16>>2]=0;c[u+20>>2]=0;c[u+24>>2]=0;c[u+28>>2]=0;A=(w|0)>1;B=0;do{if(A){z=u+(B<<2)|0;x=c[z>>2]|0;y=1;do{x=($(b[q+(y<<4<<1)>>1]|0,a[1664+(y<<1<<5)+B>>0]|0)|0)+x|0;y=y+2|0}while((y|0)<(w|0));c[z>>2]=x}B=B+1|0}while((B|0)!=8);c[s+0>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;y=0;do{x=s+(y<<2)|0;A=c[x>>2]|0;z=1;do{A=($(b[q+(z<<5<<1)>>1]|0,a[1664+(z<<2<<5)+y>>0]|0)|0)+A|0;z=z+2|0}while((z|0)<8);c[x>>2]=A;y=y+1|0}while((y|0)!=4);A=b[q>>1]<<6;z=b[q+256>>1]<<6;B=z+A|0;z=A-z|0;A=b[q+128>>1]|0;x=b[q+384>>1]|0;y=(x*36|0)+(A*83|0)|0;A=($(x,-83)|0)+(A*36|0)|0;x=y+B|0;c[v>>2]=x;c[n>>2]=A+z;c[o>>2]=z-A;c[p>>2]=B-y;y=0;while(1){B=c[s+(y<<2)>>2]|0;c[t+(y<<2)>>2]=B+x;c[t+(7-y<<2)>>2]=x-B;y=y+1|0;if((y|0)==4){x=0;break}x=c[v+(y<<2)>>2]|0}do{z=c[t+(x<<2)>>2]|0;y=c[u+(x<<2)>>2]|0;B=z+64+y|0;A=B>>7;if((A+32768|0)>>>0>65535)A=B>>31^32767;b[q+(x<<4<<1)>>1]=A;y=z-y+64|0;z=y>>7;if((z+32768|0)>>>0>65535)z=y>>31^32767;b[q+(15-x<<4<<1)>>1]=z;x=x+1|0}while((x|0)!=8);if((w|0)<16)w=(r&3|0)==0&(r|0)!=0?w+ -4|0:w;r=r+1|0;if((r|0)==16)break;else q=q+2|0}m=m?16:e;f=20-f|0;n=1<1;o=h+4|0;r=h+8|0;p=h+12|0;s=0;while(1){c[l+0>>2]=0;c[l+4>>2]=0;c[l+8>>2]=0;c[l+12>>2]=0;c[l+16>>2]=0;c[l+20>>2]=0;c[l+24>>2]=0;c[l+28>>2]=0;v=0;do{if(q){e=l+(v<<2)|0;u=c[e>>2]|0;t=1;do{u=($(b[d+(t<<1)>>1]|0,a[1664+(t<<1<<5)+v>>0]|0)|0)+u|0;t=t+2|0}while((t|0)<(m|0));c[e>>2]=u}v=v+1|0}while((v|0)!=8);c[k+0>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;e=0;do{t=k+(e<<2)|0;v=c[t>>2]|0;u=1;do{v=($(b[d+(u<<1<<1)>>1]|0,a[1664+(u<<2<<5)+e>>0]|0)|0)+v|0;u=u+2|0}while((u|0)<8);c[t>>2]=v;e=e+1|0}while((e|0)!=4);A=b[d>>1]<<6;z=b[d+16>>1]<<6;B=z+A|0;z=A-z|0;A=b[d+8>>1]|0;t=b[d+24>>1]|0;u=(t*36|0)+(A*83|0)|0;A=($(t,-83)|0)+(A*36|0)|0;t=u+B|0;c[h>>2]=t;c[o>>2]=A+z;c[r>>2]=z-A;c[p>>2]=B-u;u=0;while(1){B=c[k+(u<<2)>>2]|0;c[j+(u<<2)>>2]=B+t;c[j+(7-u<<2)>>2]=t-B;u=u+1|0;if((u|0)==4){t=0;break}t=c[h+(u<<2)>>2]|0}do{u=c[l+(t<<2)>>2]|0;v=(c[j+(t<<2)>>2]|0)+n|0;e=v+u>>f;if((e+32768|0)>>>0>65535)e=e>>31^32767;b[d+(t<<1)>>1]=e;u=v-u>>f;if((u+32768|0)>>>0>65535)u=u>>31^32767;b[d+(15-t<<1)>>1]=u;t=t+1|0}while((t|0)!=8);s=s+1|0;if((s|0)==16)break;else d=d+32|0}i=g;return}function pc(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;g=i;i=i+320|0;h=g+256|0;n=g+192|0;o=g+160|0;s=g+128|0;u=g+112|0;t=g+96|0;m=g+64|0;k=g+32|0;j=g+16|0;l=g;q=(e|0)>32;y=e+4|0;v=u+4|0;w=u+8|0;x=u+12|0;p=0;y=(y|0)>32?32:y;r=d;while(1){z=n+0|0;A=z+64|0;do{c[z>>2]=0;z=z+4|0}while((z|0)<(A|0));z=(y|0)>1;C=0;do{if(z){B=n+(C<<2)|0;A=c[B>>2]|0;D=1;do{A=($(b[r+(D<<5<<1)>>1]|0,a[1664+(D<<5)+C>>0]|0)|0)+A|0;D=D+2|0}while((D|0)<(y|0));c[B>>2]=A}C=C+1|0}while((C|0)!=16);c[s+0>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[s+16>>2]=0;c[s+20>>2]=0;c[s+24>>2]=0;c[s+28>>2]=0;z=(y|0)/2|0;A=(y|0)>3;B=0;do{if(A){C=s+(B<<2)|0;D=c[C>>2]|0;E=1;do{D=($(b[r+(E<<6<<1)>>1]|0,a[1664+(E<<1<<5)+B>>0]|0)|0)+D|0;E=E+2|0}while((E|0)<(z|0));c[C>>2]=D}B=B+1|0}while((B|0)!=8);c[t+0>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;C=0;do{z=t+(C<<2)|0;B=c[z>>2]|0;A=1;do{B=($(b[r+(A<<7<<1)>>1]|0,a[1664+(A<<2<<5)+C>>0]|0)|0)+B|0;A=A+2|0}while((A|0)<8);c[z>>2]=B;C=C+1|0}while((C|0)!=4);D=b[r>>1]<<6;C=b[r+1024>>1]<<6;E=C+D|0;C=D-C|0;D=b[r+512>>1]|0;z=b[r+1536>>1]|0;A=(z*36|0)+(D*83|0)|0;D=($(z,-83)|0)+(D*36|0)|0;z=A+E|0;c[u>>2]=z;c[v>>2]=D+C;c[w>>2]=C-D;c[x>>2]=E-A;A=0;while(1){E=c[t+(A<<2)>>2]|0;c[o+(A<<2)>>2]=E+z;c[o+(7-A<<2)>>2]=z-E;A=A+1|0;if((A|0)==4){z=0;break}z=c[u+(A<<2)>>2]|0}do{D=c[o+(z<<2)>>2]|0;E=c[s+(z<<2)>>2]|0;c[h+(z<<2)>>2]=E+D;c[h+(15-z<<2)>>2]=D-E;z=z+1|0}while((z|0)!=8);z=0;do{A=c[h+(z<<2)>>2]|0;B=c[n+(z<<2)>>2]|0;D=A+64+B|0;C=D>>7;if((C+32768|0)>>>0>65535)C=D>>31^32767;b[r+(z<<5<<1)>>1]=C;A=A-B+64|0;B=A>>7;if((B+32768|0)>>>0>65535)B=A>>31^32767;b[r+(31-z<<5<<1)>>1]=B;z=z+1|0}while((z|0)!=16);if((y|0)<32)y=(p&3|0)==0&(p|0)!=0?y+ -4|0:y;p=p+1|0;if((p|0)==32)break;else r=r+2|0}o=q?32:e;e=20-f|0;s=1<1;r=(o|0)/2|0;q=(o|0)>3;p=j+4|0;t=j+8|0;u=j+12|0;v=0;while(1){z=n+0|0;A=z+64|0;do{c[z>>2]=0;z=z+4|0}while((z|0)<(A|0));z=0;do{if(f){w=n+(z<<2)|0;y=c[w>>2]|0;x=1;do{y=($(b[d+(x<<1)>>1]|0,a[1664+(x<<5)+z>>0]|0)|0)+y|0;x=x+2|0}while((x|0)<(o|0));c[w>>2]=y}z=z+1|0}while((z|0)!=16);c[k+0>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;c[k+20>>2]=0;c[k+24>>2]=0;c[k+28>>2]=0;z=0;do{if(q){w=k+(z<<2)|0;y=c[w>>2]|0;x=1;do{E=x<<1;y=($(b[d+(E<<1)>>1]|0,a[1664+(E<<5)+z>>0]|0)|0)+y|0;x=x+2|0}while((x|0)<(r|0));c[w>>2]=y}z=z+1|0}while((z|0)!=8);c[l+0>>2]=0;c[l+4>>2]=0;c[l+8>>2]=0;c[l+12>>2]=0;w=0;do{x=l+(w<<2)|0;z=c[x>>2]|0;y=1;do{E=y<<2;z=($(b[d+(E<<1)>>1]|0,a[1664+(E<<5)+w>>0]|0)|0)+z|0;y=y+2|0}while((y|0)<8);c[x>>2]=z;w=w+1|0}while((w|0)!=4);D=b[d>>1]<<6;C=b[d+32>>1]<<6;E=C+D|0;C=D-C|0;D=b[d+16>>1]|0;w=b[d+48>>1]|0;x=(w*36|0)+(D*83|0)|0;D=($(w,-83)|0)+(D*36|0)|0;w=x+E|0;c[j>>2]=w;c[p>>2]=D+C;c[t>>2]=C-D;c[u>>2]=E-x;x=0;while(1){E=c[l+(x<<2)>>2]|0;c[m+(x<<2)>>2]=E+w;c[m+(7-x<<2)>>2]=w-E;x=x+1|0;if((x|0)==4){w=0;break}w=c[j+(x<<2)>>2]|0}do{D=c[m+(w<<2)>>2]|0;E=c[k+(w<<2)>>2]|0;c[h+(w<<2)>>2]=E+D;c[h+(15-w<<2)>>2]=D-E;w=w+1|0}while((w|0)!=8);w=0;do{x=c[n+(w<<2)>>2]|0;y=(c[h+(w<<2)>>2]|0)+s|0;z=y+x>>e;if((z+32768|0)>>>0>65535)z=z>>31^32767;b[d+(w<<1)>>1]=z;x=y-x>>e;if((x+32768|0)>>>0>65535)x=x>>31^32767;b[d+(31-w<<1)>>1]=x;w=w+1|0}while((w|0)!=16);v=v+1|0;if((v|0)==32)break;else d=d+64|0}i=g;return}function qc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0;d=i;c=14-c|0;c=((b[a>>1]|0)+1>>1)+(1<>c&65535;e=0;do{f=e<<2;b[a+(f<<1)>>1]=c;b[a+((f|1)<<1)>>1]=c;b[a+((f|2)<<1)>>1]=c;b[a+((f|3)<<1)>>1]=c;e=e+1|0}while((e|0)!=4);i=d;return}function rc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0;d=i;c=14-c|0;c=((b[a>>1]|0)+1>>1)+(1<>c&65535;e=0;do{f=e<<3;b[a+(f<<1)>>1]=c;b[a+((f|1)<<1)>>1]=c;b[a+((f|2)<<1)>>1]=c;b[a+((f|3)<<1)>>1]=c;b[a+((f|4)<<1)>>1]=c;b[a+((f|5)<<1)>>1]=c;b[a+((f|6)<<1)>>1]=c;b[a+((f|7)<<1)>>1]=c;e=e+1|0}while((e|0)!=8);i=d;return}function sc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0;d=i;e=14-c|0;e=((b[a>>1]|0)+1>>1)+(1<>e&65535;c=0;do{f=c<<4;g=0;do{b[a+(g+f<<1)>>1]=e;g=g+1|0}while((g|0)!=16);c=c+1|0}while((c|0)!=16);i=d;return}function tc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0;d=i;e=14-c|0;e=((b[a>>1]|0)+1>>1)+(1<>e&65535;c=0;do{f=c<<5;g=0;do{b[a+(g+f<<1)>>1]=e;g=g+1|0}while((g|0)!=32);c=c+1|0}while((c|0)!=32);i=d;return}function uc(a,f,g,h,j,k,l,m,n,o){a=a|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;var p=0,q=0,r=0,s=0,t=0;p=i;i=i+128|0;k=p;r=k+0|0;q=r+128|0;do{c[r>>2]=0;r=r+4|0}while((r|0)<(q|0));t=d[j+n+96>>0]|0;g=g>>>1;c[k+((t&31)<<2)>>2]=b[j+(n*10|0)+114>>1];c[k+((t+1&31)<<2)>>2]=b[j+(n*10|0)+116>>1];c[k+((t+2&31)<<2)>>2]=b[j+(n*10|0)+118>>1];c[k+((t+3&31)<<2)>>2]=b[j+(n*10|0)+120>>1];j=o+ -5|0;h=h>>>1;if((m|0)<=0){i=p;return}n=(l|0)>0;o=1<>1]|0;t=t+(c[k+(t>>>j<<2)>>2]|0)|0;if(t&q)t=0-t>>31&o;b[a+(s<<1)>>1]=t;s=s+1|0}while((s|0)!=(l|0))}r=r+1|0;if((r|0)==(m|0))break;else{a=a+(g<<1)|0;f=f+(h<<1)|0}}i=p;return}function vc(a,d,f,g,h,j,k,l,m,n,o,p,q){a=a|0;d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;var r=0,s=0,t=0,u=0,v=0,w=0;n=i;o=h+(m*10|0)+112|0;r=c[h+(m<<2)+100>>2]|0;f=f>>>1;g=g>>>1;if((r|0)!=1){if(c[j>>2]|0){u=b[o>>1]|0;if((l|0)>0){p=1<>1]|0)+u|0;if(v&t)v=0-v>>31&p;b[a+(($(s,f)|0)<<1)>>1]=v;s=s+1|0}while((s|0)!=(l|0));p=1}else p=1}else p=0;if(c[j+8>>2]|0){s=b[o>>1]|0;k=k+ -1|0;if((l|0)>0){v=1<>1]|0)+s|0;if(w&u)w=0-w>>31&v;b[a+(($(t,f)|0)+k<<1)>>1]=w;t=t+1|0}while((t|0)!=(l|0))}}if(!r){u=l;v=p;w=0;t=k;Dc(a,d,f,g,h,t,u,m,v,w,q);i=n;return}}else p=0;if(c[j+4>>2]|0){r=b[o>>1]|0;if((p|0)<(k|0)){s=1<>1]|0)+r|0;if(v&t)v=0-v>>31&s;b[a+(u<<1)>>1]=v;u=u+1|0}while((u|0)!=(k|0));r=1}else r=1}else r=0;if(!(c[j+12>>2]|0)){u=l;v=p;w=r;t=k;Dc(a,d,f,g,h,t,u,m,v,w,q);i=n;return}j=b[o>>1]|0;t=l+ -1|0;o=$(t,f)|0;u=$(t,g)|0;if((p|0)>=(k|0)){u=t;v=p;w=r;t=k;Dc(a,d,f,g,h,t,u,m,v,w,q);i=n;return}s=1<>1]|0)+j|0;if(w&l)w=0-w>>31&s;b[a+(v+o<<1)>>1]=w;v=v+1|0}while((v|0)!=(k|0));Dc(a,d,f,g,h,k,t,m,p,r,q);i=n;return}function wc(d,f,g,h,j,k,l,m,n,o,p,q,r){d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;var s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;t=i;D=j+(n*10|0)+112|0;C=c[j+(n<<2)+100>>2]|0;g=g>>>1;h=h>>>1;B=(C|0)!=1;if(B){if(c[k>>2]|0){I=b[D>>1]|0;if((m|0)>0){H=1<>1]|0)+I|0;if(J&G)J=0-J>>31&H;b[d+(($(F,g)|0)<<1)>>1]=J;F=F+1|0}while((F|0)!=(m|0));F=1}else F=1}else F=0;if(c[k+8>>2]|0){G=b[D>>1]|0;l=l+ -1|0;if((m|0)>0){J=1<>1]|0)+G|0;if(K&I)K=0-K>>31&J;b[d+(($(H,g)|0)+l<<1)>>1]=K;H=H+1|0}while((H|0)!=(m|0))}}if(!C){D=1;G=0}else E=15}else{F=0;E=15}if((E|0)==15){if(c[k+4>>2]|0){H=b[D>>1]|0;if((F|0)<(l|0)){I=1<>1]|0)+H|0;if(J&G)J=0-J>>31&I;b[d+(E<<1)>>1]=J;E=E+1|0}while((E|0)!=(l|0));G=1}else G=1}else G=0;if(c[k+12>>2]|0){D=b[D>>1]|0;m=m+ -1|0;I=$(m,g)|0;H=$(m,h)|0;if((F|0)<(l|0)){K=1<>1]|0)+D|0;if(L&J)L=0-L>>31&K;b[d+(E+I<<1)>>1]=L;E=E+1|0}while((E|0)!=(l|0));D=0}else D=0}else D=0}Dc(d,f,g,h,j,l,m,n,F,G,r);r=(C|0)==2;if((a[q>>0]|0)==0&r?(c[k>>2]|0)==0:0)j=(c[k+4>>2]|0)==0;else j=0;H=j&1;j=q+1|0;C=(C|0)==3;if((a[j>>0]|0)==0&C?(c[k+4>>2]|0)==0:0)n=(c[k+8>>2]|0)==0;else n=0;I=n&1;n=q+2|0;if((a[n>>0]|0)==0&r?(c[k+8>>2]|0)==0:0)E=(c[k+12>>2]|0)==0;else E=0;J=E&1;E=q+3|0;if((a[E>>0]|0)==0&C?(c[k>>2]|0)==0:0)k=(c[k+12>>2]|0)==0;else k=0;k=k&1;B=B^1;if(!((a[o>>0]|0)==0|B)?(A=H+G|0,z=m-k|0,(A|0)<(z|0)):0)do{b[d+(($(A,g)|0)<<1)>>1]=b[f+(($(A,h)|0)<<1)>>1]|0;A=A+1|0}while((A|0)!=(z|0));if(!((a[o+1>>0]|0)==0|B)?(y=I+G|0,x=m-J|0,(y|0)<(x|0)):0){z=l+ -1|0;do{b[d+(z+($(y,g)|0)<<1)>>1]=b[f+(z+($(y,h)|0)<<1)>>1]|0;y=y+1|0}while((y|0)!=(x|0))}if(!((a[p>>0]|0)==0|D)?(w=H+F|0,v=l-I|0,(w|0)<(v|0)):0)do{b[d+(w<<1)>>1]=b[f+(w<<1)>>1]|0;w=w+1|0}while((w|0)!=(v|0));if(!((a[p+1>>0]|0)==0|D)?(u=k+F|0,s=l-J|0,(u|0)<(s|0)):0){v=m+ -1|0;p=$(v,h)|0;v=$(v,g)|0;do{b[d+(u+v<<1)>>1]=b[f+(u+p<<1)>>1]|0;u=u+1|0}while((u|0)!=(s|0))}if((a[q>>0]|0)!=0&r)b[d>>1]=b[f>>1]|0;if((a[j>>0]|0)!=0&C){L=l+ -1|0;b[d+(L<<1)>>1]=b[f+(L<<1)>>1]|0}if((a[n>>0]|0)!=0&r){L=m+ -1|0;K=l+ -1|0;b[d+(K+($(L,g)|0)<<1)>>1]=b[f+(K+($(L,h)|0)<<1)>>1]|0}if(!((a[E>>0]|0)!=0&C)){i=t;return}L=m+ -1|0;b[d+(($(L,g)|0)<<1)>>1]=b[f+(($(L,h)|0)<<1)>>1]|0;i=t;return}function xc(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;h=i;Cc(a,b,2,c,d,e,f,g);i=h;return}function yc(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;h=i;Cc(a,2,b,c,d,e,f,g);i=h;return}function zc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=i;Bc(a,b,2,c,d,e,f);i=g;return}function Ac(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=i;Bc(a,2,b,c,d,e,f);i=g;return}function Bc(d,f,g,h,j,k,l){d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;m=i;f=f>>>1;p=g>>>1;o=l+ -8|0;g=$(f,-2)|0;n=0-f|0;r=1<>2]<=1){v=0-s|0;u=(a[j+l>>0]|0)==0;t=(a[k+l>>0]|0)==0;x=0;w=d;while(1){y=w+(n<<1)|0;B=e[y>>1]|0;z=e[w>>1]|0;A=(e[w+(g<<1)>>1]|0)+4-(e[w+(f<<1)>>1]|0)+(z-B<<2)>>3;if((A|0)<(v|0))A=v;else A=(A|0)>(s|0)?s:A;if(u){B=A+B|0;if(B&q)B=0-B>>31&r;b[y>>1]=B}if(t){y=z-A|0;if(y&q)y=0-y>>31&r;b[w>>1]=y}x=x+1|0;if((x|0)==4)break;else w=w+(p<<1)|0}}l=l+1|0;if((l|0)==2)break;else d=d+(p<<2<<1)|0}i=m;return}function Cc(d,f,g,h,j,k,l,m){d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0;n=i;f=f>>>1;g=g>>>1;o=m+ -8|0;y=h<>3;u=y>>2;q=$(f,-4)|0;p=f*3|0;v=C+q|0;F=(g+f|0)*3|0;t=(y>>1)+y>>3;H=1<>1]|0;X=b[d+(s<<1)>>1]|0;W=b[d+(w<<1)>>1]|0;da=W&65535;R=(Y&65535)-((X&65535)<<1)+da|0;R=(R|0)>-1?R:0-R|0;T=b[d+(h<<1)>>1]|0;U=b[d+(f<<1)>>1]|0;V=b[d>>1]|0;M=V&65535;S=(T&65535)-((U&65535)<<1)+M|0;S=(S|0)>-1?S:0-S|0;ba=e[d+(z<<1)>>1]|0;Q=(e[d+(A<<1)>>1]|0)-((e[d+(B<<1)>>1]|0)<<1)+ba|0;Q=(Q|0)>-1?Q:0-Q|0;ca=e[d+(C<<1)>>1]|0;Z=(e[d+(D<<1)>>1]|0)-((e[d+(E<<1)>>1]|0)<<1)+ca|0;Z=(Z|0)>-1?Z:0-Z|0;L=S+R|0;aa=Z+Q|0;K=c[j+(I<<2)>>2]<>0]|0;P=a[l+I>>0]|0;do if((aa+L|0)<(y|0)){N=(K*5|0)+1>>1;ea=(e[d+(q<<1)>>1]|0)-da|0;O=b[d+(p<<1)>>1]|0;fa=(O&65535)-M|0;if((((((((fa|0)>-1?fa:0-fa|0)+((ea|0)>-1?ea:0-ea|0)|0)<(x|0)?(fa=da-M|0,(((fa|0)>-1?fa:0-fa|0)|0)<(N|0)):0)?(fa=(e[d+(v<<1)>>1]|0)-ba|0,ea=(e[d+(F<<1)>>1]|0)-ca|0,(((ea|0)>-1?ea:0-ea|0)+((fa|0)>-1?fa:0-fa|0)|0)<(x|0)):0)?(fa=ba-ca|0,(((fa|0)>-1?fa:0-fa|0)|0)<(N|0)):0)?(L<<1|0)<(u|0):0)?(aa<<1|0)<(u|0):0){K=K<<1;L=_<<24>>24==0;M=0-K|0;N=P<<24>>24==0;ba=O;P=1;O=d;while(1){Z=O+(r<<1)|0;Y=Y&65535;_=O+(s<<1)|0;X=X&65535;aa=O+(w<<1)|0;R=W&65535;V=V&65535;W=O+(f<<1)|0;U=U&65535;Q=O+(h<<1)|0;S=T&65535;T=ba&65535;if(L){ba=e[O+(q<<1)>>1]|0;ca=(Y+4+U+(R+X+V<<1)>>3)-R|0;if((ca|0)<(M|0))ca=M;else ca=(ca|0)>(K|0)?K:ca;b[aa>>1]=ca+R;aa=((Y+2+X+R+V|0)>>>2)-X|0;if((aa|0)<(M|0))aa=M;else aa=(aa|0)>(K|0)?K:aa;b[_>>1]=aa+X;_=((Y*3|0)+4+X+R+V+(ba<<1)>>3)-Y|0;if((_|0)<(M|0))_=M;else _=(_|0)>(K|0)?K:_;b[Z>>1]=_+Y}if(N){X=(X+4+S+(V+R+U<<1)>>3)-V|0;if((X|0)<(M|0))X=M;else X=(X|0)>(K|0)?K:X;b[O>>1]=X+V;X=((R+2+V+U+S|0)>>>2)-U|0;if((X|0)<(M|0))X=M;else X=(X|0)>(K|0)?K:X;b[W>>1]=X+U;R=(R+4+V+U+(S*3|0)+(T<<1)>>3)-S|0;if((R|0)<(M|0))R=M;else R=(R|0)>(K|0)?K:R;b[Q>>1]=R+S}Q=O+(g<<1)|0;if((P|0)==4)break;Y=b[O+(g+r<<1)>>1]|0;X=b[O+(g+s<<1)>>1]|0;W=b[O+(g-f<<1)>>1]|0;V=b[Q>>1]|0;U=b[O+(g+f<<1)>>1]|0;T=b[O+(g+h<<1)>>1]|0;ba=b[O+(g+p<<1)>>1]|0;P=P+1|0;O=Q}d=d+(J<<1)|0;break}L=K>>1;N=K*10|0;M=0-K|0;O=_<<24>>24!=0;P=P<<24>>24!=0;Q=(Q+R|0)<(t|0)&(O^1);R=0-L|0;S=(Z+S|0)<(t|0)&(P^1);_=V;ba=U;U=1;V=d;while(1){aa=Y&65535;Y=V+(s<<1)|0;Z=X&65535;da=V+(w<<1)|0;ca=W&65535;_=_&65535;W=V+(f<<1)|0;X=ba&65535;T=T&65535;ba=((_-ca|0)*9|0)+8+($(X-Z|0,-3)|0)>>4;if((((ba|0)>-1?ba:0-ba|0)|0)<(N|0)){if((ba|0)<(M|0))ba=M;else ba=(ba|0)>(K|0)?K:ba;if(!O){ea=ba+ca|0;if(ea&G)ea=0-ea>>31&H;b[da>>1]=ea}if(!P){da=_-ba|0;if(da&G)da=0-da>>31&H;b[V>>1]=da}if(Q){aa=((aa+1+ca|0)>>>1)-Z+ba>>1;if((aa|0)<(R|0))aa=R;else aa=(aa|0)>(L|0)?L:aa;Z=aa+Z|0;if(Z&G)Z=0-Z>>31&H;b[Y>>1]=Z}if(S){T=((_+1+T|0)>>>1)-X-ba>>1;if((T|0)<(R|0))T=R;else T=(T|0)>(L|0)?L:T;T=T+X|0;if(T&G)T=0-T>>31&H;b[W>>1]=T}}Z=V+(g<<1)|0;if((U|0)==4)break;Y=b[V+(g+r<<1)>>1]|0;X=b[V+(g+s<<1)>>1]|0;W=b[V+(g-f<<1)>>1]|0;_=b[Z>>1]|0;ba=b[V+(g+f<<1)>>1]|0;T=b[V+(g+h<<1)>>1]|0;U=U+1|0;V=Z}d=d+(J<<1)|0}else d=d+(m<<1)|0;while(0);I=I+1|0}while((I|0)!=2);i=n;return}function Dc(e,f,g,h,j,k,l,m,n,o,p){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;var q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;t=i;x=c[j+(m<<2)+100>>2]|0;r=a[2728+(x<<2)>>0]|0;q=a[2730+(x<<2)>>0]|0;if((o|0)>=(l|0)){i=t;return}s=(n|0)<(k|0);v=1<>0]|0)+o|0,h)|0;y=$((a[2731+(x<<2)>>0]|0)+o|0,h)|0;x=$(o,g)|0;z=$(o,h)|0;while(1){if(s){o=p+r|0;A=y+q|0;B=n;do{C=b[f+(B+z<<1)>>1]|0;D=b[f+(o+B<<1)>>1]|0;if((C&65535)>(D&65535))D=3;else D=((C<<16>>16!=D<<16>>16)<<31>>31)+2|0;E=b[f+(A+B<<1)>>1]|0;if((C&65535)>(E&65535))E=1;else E=(C<<16>>16!=E<<16>>16)<<31>>31;C=(b[j+(m*10|0)+(d[2720+(E+D)>>0]<<1)+112>>1]|0)+(C&65535)|0;if(C&u)C=0-C>>31&v;b[e+(B+x<<1)>>1]=C;B=B+1|0}while((B|0)!=(k|0))}w=w+1|0;if((w|0)==(l|0))break;else{p=p+h|0;y=y+h|0;x=x+g|0;z=z+h|0}}i=t;return}function Ec(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;j=i;k=c[b+136>>2]|0;l=(c[b+200>>2]|0)+13080|0;r=(1<>2])+ -1|0;o=r&e;n=r&f;q=(n|0)!=0|(a[k+309>>0]|0)!=0;m=q&1;c[k+31296>>2]=m;p=(o|0)!=0|(a[k+308>>0]|0)!=0;b=p&1;c[k+31292>>2]=b;if(!(r&(f|e)))p=d[k+311>>0]|0;else p=p&q&1;c[k+31300>>2]=p;if((o+g|0)==(1<>2]|0))m=(a[k+310>>0]|0)!=0&(n|0)==0&1;c[k+31308>>2]=m;if(!m){q=0;q=q&1;r=k+31304|0;c[r>>2]=q;r=h+f|0;q=k+316|0;q=c[q>>2]|0;q=(r|0)<(q|0);q=q?b:0;r=k+31288|0;c[r>>2]=q;i=j;return}q=(g+e|0)<(c[k+312>>2]|0);q=q&1;r=k+31304|0;c[r>>2]=q;r=h+f|0;q=k+316|0;q=c[q>>2]|0;q=(r|0)<(q|0);q=q?b:0;r=k+31288|0;c[r>>2]=q;i=j;return}function Fc(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;f=i;i=i+16|0;e=f;h=c[b+136>>2]|0;j=h+204|0;k=ud(13196)|0;c[e>>2]=k;if(!k){u=-12;i=f;return u|0}k=c[k+4>>2]|0;m=ud(468)|0;if(!m){u=-12;i=f;return u|0}l=c[m+4>>2]|0;c[l+4>>2]=1;o=l+8|0;c[o>>2]=1;a[l>>0]=0;c[l+348>>2]=1;q=l+352|0;n=l+380|0;r=l+408|0;p=0;do{c[q+(p<<2)>>2]=1;c[n+(p<<2)>>2]=0;c[r+(p<<2)>>2]=-1;p=p+1|0}while((p|0)<(c[o>>2]|0));c[l+436>>2]=0;c[l+440>>2]=1;a[l+444>>0]=0;p=b+208|0;wd(p);c[p>>2]=m;c[k>>2]=0;p=k+72|0;c[p>>2]=1;u=ad(j,8)|0;q=k+4|0;c[q>>2]=u;do if((u|0)<=3){a[k+8>>0]=0;o=k+13120|0;c[o>>2]=ed(j,32)|0;m=ed(j,32)|0;n=k+13124|0;c[n>>2]=m;m=Sc(c[o>>2]|0,m,0,c[b+4>>2]|0)|0;if((m|0)>=0){l=k+52|0;c[l>>2]=(ad(j,8)|0)+8;q=c[q>>2]|0;if(!q){c[k+60>>2]=32;q=32}else if((q|0)==2){c[k+60>>2]=56;q=56}else if((q|0)==1){c[k+60>>2]=54;q=54}else{c[k+60>>2]=58;q=58}c[k+56>>2]=1;q=Cd(q)|0;if(q){c[k+13180>>2]=0;c[k+13168>>2]=0;u=d[q+5>>0]|0;c[k+13172>>2]=u;c[k+13176>>2]=u;u=d[q+6>>0]|0;c[k+13184>>2]=u;c[k+13188>>2]=u;c[k+64>>2]=8;if((c[p>>2]|0)>0){q=k+76|0;r=0;do{c[q+(r*12|0)>>2]=1;c[q+(r*12|0)+4>>2]=0;c[q+(r*12|0)+8>>2]=-1;r=r+1|0}while((r|0)<(c[p>>2]|0))}t=(fd(j)|0)+3|0;u=k+13064|0;c[u>>2]=t;t=1<>2]=s+(c[o>>2]|0)&t;c[n>>2]=s+(c[n>>2]|0)&t;t=k+13068|0;c[t>>2]=fd(j)|0;s=k+13072|0;c[s>>2]=(fd(j)|0)+2;p=fd(j)|0;q=c[s>>2]|0;r=k+13076|0;c[r>>2]=q+p;if(q>>>0<(c[u>>2]|0)>>>0){q=k+13088|0;c[q>>2]=0;p=k+13092|0;c[p>>2]=fd(j)|0;a[k+12941>>0]=dd(j)|0;v=dd(j)|0;c[k+68>>2]=v;if(v){v=k+13044|0;a[v>>0]=(ad(j,4)|0)+1;a[k+13045>>0]=(ad(j,4)|0)+1;w=(fd(j)|0)+3|0;c[k+13048>>2]=w;c[k+13052>>2]=w+(fd(j)|0);if((d[v>>0]|0|0)>(c[l>>2]|0)){m=-1094995529;break}a[k+13056>>0]=dd(j)|0}c[k+2184>>2]=0;a[k+12942>>0]=0;a[k+13060>>0]=0;a[k+13061>>0]=dd(j)|0;c[k+160>>2]=0;c[k+164>>2]=1;if((dd(j)|0)!=0?(w=dd(j)|0,cd(j,7),(w|0)!=0):0){c[k+13096>>2]=dd(j)|0;c[k+13100>>2]=dd(j)|0;c[k+13104>>2]=dd(j)|0;c[k+13108>>2]=dd(j)|0;dd(j)|0;c[k+13112>>2]=dd(j)|0;dd(j)|0;c[k+13116>>2]=dd(j)|0;dd(j)|0}j=c[o>>2]|0;c[k+12>>2]=j;o=c[n>>2]|0;c[k+16>>2]=o;u=c[u>>2]|0;w=(c[t>>2]|0)+u|0;c[k+13080>>2]=w;t=u+ -1|0;c[k+13084>>2]=t;n=1<>w;c[k+13128>>2]=v;n=o+ -1+n>>w;c[k+13132>>2]=n;c[k+13136>>2]=$(n,v)|0;c[k+13140>>2]=j>>u;c[k+13144>>2]=o>>u;v=c[s>>2]|0;c[k+13148>>2]=j>>v;c[k+13152>>2]=o>>v;c[k+13156>>2]=j>>t;c[k+13160>>2]=o>>t;v=w-v|0;c[k+13164>>2]=(1<>2]=((c[l>>2]|0)*6|0)+ -48;u=(1<>>0>6):0)?(c[q>>2]|0)>>>0<=v>>>0:0)?(c[p>>2]|0)>>>0<=v>>>0:0)?(c[r>>2]|0)>>>0<=(w>>>0>5?5:w)>>>0:0)?((c[h+216>>2]|0)-(c[h+212>>2]|0)|0)>=0:0){h=b+272|0;j=c[h>>2]|0;if((j|0)!=0?(w=c[e>>2]|0,(Vd(c[j+4>>2]|0,c[w+4>>2]|0,c[w+8>>2]|0)|0)==0):0){wd(e);w=0;i=f;return w|0}else j=0;do{k=b+(j<<2)+400|0;l=c[k>>2]|0;do if(l){if(c[c[l+4>>2]>>2]|0)break;wd(k)}while(0);j=j+1|0}while((j|0)!=256);j=c[h>>2]|0;do if((j|0)!=0?(g=b+200|0,(c[g>>2]|0)==(c[j+4>>2]|0)):0){v=b+1424|0;wd(v);w=vd(c[h>>2]|0)|0;c[v>>2]=w;if(w)break;c[g>>2]=0}while(0);wd(h);c[h>>2]=c[e>>2];w=0;i=f;return w|0}}else m=-1094995529}else m=-22}}else m=-1094995529;while(0);wd(e);w=m;i=f;return w|0}function Gc(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0;f=i;i=i+16|0;e=f+4|0;j=f;l=b+136|0;g=c[l>>2]|0;n=g+204|0;h=nd(1692)|0;c[j>>2]=h;if(!h){I=-12;i=f;return I|0}I=rd(h,1692,6,0,0)|0;c[e>>2]=I;if(!I){kd(j);I=-12;i=f;return I|0}a[(c[j>>2]|0)+53>>0]=1;h=c[j>>2]|0;c[h+44>>2]=1;c[h+48>>2]=1;a[h+52>>0]=1;a[(c[j>>2]|0)+57>>0]=0;h=c[j>>2]|0;c[h+60>>2]=0;c[h+64>>2]=0;a[h+1629>>0]=2;h=fd(n)|0;a:do if((h>>>0<=255?(k=fd(n)|0,c[c[j>>2]>>2]=k,k>>>0<=31):0)?(m=c[b+(k<<2)+272>>2]|0,(m|0)!=0):0){k=c[m+4>>2]|0;I=(dd(n)|0)&255;a[(c[j>>2]|0)+41>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+39>>0]=I;I=ad(n,3)|0;c[(c[j>>2]|0)+1624>>2]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+4>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+5>>0]=I;I=(fd(n)|0)+1|0;c[(c[j>>2]|0)+8>>2]=I;I=(fd(n)|0)+1|0;c[(c[j>>2]|0)+12>>2]=I;I=gd(n)|0;c[(c[j>>2]|0)+16>>2]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+20>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+21>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+22>>0]=I;I=c[j>>2]|0;c[I+24>>2]=0;if(a[I+22>>0]|0){I=fd(n)|0;c[(c[j>>2]|0)+24>>2]=I}I=gd(n)|0;c[(c[j>>2]|0)+28>>2]=I;if((I+12|0)>>>0<=24?(I=gd(n)|0,c[(c[j>>2]|0)+32>>2]=I,(I+12|0)>>>0<=24):0){I=(dd(n)|0)&255;a[(c[j>>2]|0)+36>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+37>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+38>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+40>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+42>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+43>>0]=I;if(a[(c[j>>2]|0)+42>>0]|0){m=(fd(n)|0)+1|0;c[(c[j>>2]|0)+44>>2]=m;m=(fd(n)|0)+1|0;o=c[j>>2]|0;c[o+48>>2]=m;o=c[o+44>>2]|0;if(!o){b=-1094995529;break}if((m|0)==0?1:(o|0)>=(c[k+13120>>2]|0)){b=-1094995529;break}if((m|0)>=(c[k+13124>>2]|0)){b=-1094995529;break}m=pd(o,4)|0;c[(c[j>>2]|0)+1648>>2]=m;m=pd(c[(c[j>>2]|0)+48>>2]|0,4)|0;c[(c[j>>2]|0)+1652>>2]=m;m=c[j>>2]|0;if(!(c[m+1648>>2]|0)){b=-12;break}if(!(c[m+1652>>2]|0)){b=-12;break}p=(dd(n)|0)&255;a[(c[j>>2]|0)+52>>0]=p;p=c[j>>2]|0;if(!(a[p+52>>0]|0)){q=(c[p+44>>2]|0)+ -1|0;if((q|0)>0){o=0;m=0;r=0;do{q=(fd(n)|0)+1|0;p=c[j>>2]|0;c[(c[p+1648>>2]|0)+(r<<2)>>2]=q;o=_d(q|0,0,o|0,m|0)|0;m=D;r=r+1|0;q=(c[p+44>>2]|0)+ -1|0}while((r|0)<(q|0))}else{m=0;o=0}r=c[k+13128>>2]|0;s=((r|0)<0)<<31>>31;if(!(m>>>0>>0|(m|0)==(s|0)&o>>>0>>0)){b=-1094995529;break}I=Zd(r|0,s|0,o|0,m|0)|0;c[(c[p+1648>>2]|0)+(q<<2)>>2]=I;q=(c[p+48>>2]|0)+ -1|0;if((q|0)>0){p=0;o=0;r=0;do{q=(fd(n)|0)+1|0;m=c[j>>2]|0;c[(c[m+1652>>2]|0)+(r<<2)>>2]=q;p=_d(q|0,0,p|0,o|0)|0;o=D;r=r+1|0;q=(c[m+48>>2]|0)+ -1|0}while((r|0)<(q|0))}else{m=p;o=0;p=0}r=c[k+13132>>2]|0;s=((r|0)<0)<<31>>31;if(!(o>>>0>>0|(o|0)==(s|0)&p>>>0>>0)){b=-1094995529;break}I=Zd(r|0,s|0,p|0,o|0)|0;c[(c[m+1652>>2]|0)+(q<<2)>>2]=I}I=(dd(n)|0)&255;a[(c[j>>2]|0)+53>>0]=I}I=(dd(n)|0)&255;a[(c[j>>2]|0)+54>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+55>>0]=I;if((a[(c[j>>2]|0)+55>>0]|0)!=0?(I=(dd(n)|0)&255,a[(c[j>>2]|0)+56>>0]=I,I=(dd(n)|0)&255,a[(c[j>>2]|0)+57>>0]=I,(a[(c[j>>2]|0)+57>>0]|0)==0):0){m=(gd(n)|0)<<1;c[(c[j>>2]|0)+60>>2]=m;m=(gd(n)|0)<<1;I=c[j>>2]|0;c[I+64>>2]=m;if(((c[I+60>>2]|0)+13|0)>>>0>26){b=-1094995529;break}if((m+13|0)>>>0>26){b=-1094995529;break}}p=(dd(n)|0)&255;a[(c[j>>2]|0)+68>>0]=p;p=c[j>>2]|0;if(a[p+68>>0]|0){q=0;do{o=p+(q<<6)+69|0;m=o+16|0;do{a[o>>0]=16;o=o+1|0}while((o|0)<(m|0));a[p+q+1605>>0]=16;a[p+q+1611>>0]=16;q=q+1|0}while((q|0)!=6);o=p+453|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+517|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+581|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+645|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+709|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+773|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+837|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+901|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+965|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1029|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1093|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1157|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1221|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1285|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1349|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1413|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1477|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1541|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));m=c[j>>2]|0;v=(c[l>>2]|0)+204|0;w=0;do{p=(w|0)>0?64:16;q=(w|0)>1;o=w+ -2|0;x=(w|0)==3?3:1;r=1<<(w<<1)+4;t=(r|0)>0;s=(w|0)==0;r=(r|0)<64?r:64;u=0;do{if(!(((dd(v)|0)&255)<<24>>24)){y=fd(v)|0;if(y){if(u>>>0>>0){b=-1094995529;break a}y=u-y|0;ce(m+(w*384|0)+(u<<6)+69|0,m+(w*384|0)+(y<<6)+69|0,p|0)|0;if(q)a[m+(o*6|0)+u+1605>>0]=a[m+(o*6|0)+y+1605>>0]|0}}else{if(q){z=(gd(v)|0)+8|0;a[m+(o*6|0)+u+1605>>0]=z}else z=8;if(t){y=0;do{if(s)A=(d[24+y>>0]<<2)+(d[8+y>>0]|0)|0;else A=(d[104+y>>0]<<3)+(d[40+y>>0]|0)|0;z=(z+256+(gd(v)|0)|0)%256|0;a[m+(w*384|0)+(u<<6)+A+69>>0]=z;y=y+1|0}while((y|0)!=(r|0))}}u=u+x|0}while((u|0)<6);w=w+1|0}while((w|0)<4);if((c[k+4>>2]|0)==3){o=0;do{a[m+o+1285>>0]=a[m+o+901>>0]|0;a[m+o+1349>>0]=a[m+o+965>>0]|0;a[m+o+1477>>0]=a[m+o+1093>>0]|0;a[m+o+1541>>0]=a[m+o+1157>>0]|0;o=o+1|0}while((o|0)!=64);a[m+1612>>0]=a[m+1606>>0]|0;a[m+1613>>0]=a[m+1607>>0]|0;a[m+1615>>0]=a[m+1609>>0]|0;a[m+1616>>0]=a[m+1610>>0]|0}}I=(dd(n)|0)&255;a[(c[j>>2]|0)+1617>>0]=I;I=(fd(n)|0)+2|0;c[(c[j>>2]|0)+1620>>2]=I;m=k+13080|0;if(I>>>0<=(c[m>>2]|0)>>>0){I=(dd(n)|0)&255;a[(c[j>>2]|0)+1628>>0]=I;do if((dd(n)|0)!=0?(I=dd(n)|0,ad(n,7)|0,(I|0)!=0):0){n=c[j>>2]|0;p=(c[l>>2]|0)+204|0;if(a[n+21>>0]|0)a[n+1629>>0]=(fd(p)|0)+2;a[n+1630>>0]=dd(p)|0;I=(dd(p)|0)&255;a[n+1631>>0]=I;if(I<<24>>24){a[n+1632>>0]=fd(p)|0;I=fd(p)|0;o=n+1633|0;a[o>>0]=I;if((I&255)>>>0<5)l=0;else break;while(1){a[n+l+1634>>0]=gd(p)|0;a[n+l+1639>>0]=gd(p)|0;if((l|0)<(d[o>>0]|0))l=l+1|0;else break}}a[n+1644>>0]=fd(p)|0;a[n+1645>>0]=fd(p)|0}while(0);l=pd((c[(c[j>>2]|0)+44>>2]|0)+1|0,4)|0;c[(c[j>>2]|0)+1656>>2]=l;l=pd((c[(c[j>>2]|0)+48>>2]|0)+1|0,4)|0;c[(c[j>>2]|0)+1660>>2]=l;l=k+13128|0;o=pd(c[l>>2]|0,4)|0;c[(c[j>>2]|0)+1664>>2]=o;o=c[j>>2]|0;n=c[o+1656>>2]|0;if(((n|0)!=0?(c[o+1660>>2]|0)!=0:0)?(c[o+1664>>2]|0)!=0:0){if(a[o+52>>0]|0){p=c[o+1648>>2]|0;if(!p){o=pd(c[o+44>>2]|0,4)|0;c[(c[j>>2]|0)+1648>>2]=o;o=pd(c[(c[j>>2]|0)+48>>2]|0,4)|0;c[(c[j>>2]|0)+1652>>2]=o;o=c[j>>2]|0;p=c[o+1648>>2]|0;if(!p){b=-12;break}}n=c[o+1652>>2]|0;if(!n){b=-12;break}q=o+44|0;s=c[q>>2]|0;if((s|0)>0){r=0;do{I=r;r=r+1|0;H=c[l>>2]|0;c[p+(I<<2)>>2]=(($(H,r)|0)/(s|0)|0)-(($(H,I)|0)/(s|0)|0);s=c[q>>2]|0}while((r|0)<(s|0))}q=o+48|0;s=c[q>>2]|0;if((s|0)>0){p=k+13132|0;r=0;do{I=r;r=r+1|0;H=c[p>>2]|0;c[n+(I<<2)>>2]=(($(H,r)|0)/(s|0)|0)-(($(H,I)|0)/(s|0)|0);s=c[q>>2]|0}while((r|0)<(s|0))}n=c[o+1656>>2]|0}c[n>>2]=0;q=o+44|0;if((c[q>>2]|0)>0){p=c[o+1648>>2]|0;r=0;s=0;do{r=(c[p+(s<<2)>>2]|0)+r|0;s=s+1|0;c[n+(s<<2)>>2]=r}while((s|0)<(c[q>>2]|0))}s=c[o+1660>>2]|0;c[s>>2]=0;r=o+48|0;if((c[r>>2]|0)>0){q=c[o+1652>>2]|0;t=0;p=0;do{t=(c[q+(p<<2)>>2]|0)+t|0;p=p+1|0;c[s+(p<<2)>>2]=t}while((p|0)<(c[r>>2]|0))}r=c[l>>2]|0;if((r|0)>0){o=c[o+1664>>2]|0;p=0;q=0;do{q=(p>>>0>(c[n+(q<<2)>>2]|0)>>>0&1)+q|0;c[o+(p<<2)>>2]=q;p=p+1|0;r=c[l>>2]|0}while((p|0)<(r|0))}x=$(c[k+13132>>2]|0,r)|0;n=pd(x,4)|0;c[(c[j>>2]|0)+1668>>2]=n;n=pd(x,4)|0;c[(c[j>>2]|0)+1672>>2]=n;n=pd(x,4)|0;c[(c[j>>2]|0)+1676>>2]=n;n=k+13164|0;q=(c[n>>2]|0)+2|0;q=pd($(q,q)|0,4)|0;c[(c[j>>2]|0)+1688>>2]=q;q=c[j>>2]|0;p=c[q+1668>>2]|0;if(!p){b=-12;break}w=c[q+1672>>2]|0;if(!w){b=-12;break}o=c[q+1676>>2]|0;if(!o){b=-12;break}if(!(c[q+1688>>2]|0)){b=-12;break}if((x|0)>0){B=q+44|0;r=q+48|0;s=c[q+1660>>2]|0;v=c[q+1648>>2]|0;u=c[q+1656>>2]|0;t=q+1652|0;A=0;do{C=c[l>>2]|0;y=(A|0)%(C|0)|0;z=(A|0)/(C|0)|0;G=c[B>>2]|0;E=0;while(1){if((E|0)>=(G|0)){E=0;break}F=E+1|0;if(y>>>0<(c[u+(F<<2)>>2]|0)>>>0)break;else E=F}H=c[r>>2]|0;F=0;while(1){if((F|0)>=(H|0)){F=0;break}G=F+1|0;if(z>>>0<(c[s+(G<<2)>>2]|0)>>>0)break;else F=G}if((E|0)>0){G=c[(c[t>>2]|0)+(F<<2)>>2]|0;H=0;I=0;do{I=($(c[v+(H<<2)>>2]|0,G)|0)+I|0;H=H+1|0}while((H|0)!=(E|0))}else I=0;if((F|0)>0){G=c[t>>2]|0;H=0;do{I=($(c[G+(H<<2)>>2]|0,C)|0)+I|0;H=H+1|0}while((H|0)!=(F|0))}H=$(c[v+(E<<2)>>2]|0,z-(c[s+(F<<2)>>2]|0)|0)|0;I=I+y+H-(c[u+(E<<2)>>2]|0)|0;c[p+(A<<2)>>2]=I;c[w+(I<<2)>>2]=A;A=A+1|0}while((A|0)!=(x|0))}else r=q+48|0;x=c[r>>2]|0;if((x|0)>0){s=q+44|0;t=q+1660|0;q=q+1656|0;z=c[s>>2]|0;u=0;w=0;while(1){v=u;u=u+1|0;if((z|0)>0){x=c[t>>2]|0;y=x+(u<<2)|0;G=c[y>>2]|0;B=z;z=0;do{E=c[x+(v<<2)>>2]|0;A=z;z=z+1|0;if(E>>>0>>0){B=c[q>>2]|0;C=B+(z<<2)|0;F=c[C>>2]|0;do{H=c[B+(A<<2)>>2]|0;if(H>>>0>>0){do{c[o+(c[p+(($(c[l>>2]|0,E)|0)+H<<2)>>2]<<2)>>2]=w;H=H+1|0;F=c[C>>2]|0}while(H>>>0>>0);G=c[y>>2]|0}E=E+1|0}while(E>>>0>>0);B=c[s>>2]|0}w=w+1|0}while((z|0)<(B|0));v=c[r>>2]|0;z=B}else v=x;if((u|0)>=(v|0))break;else x=v}}else w=0;o=pd(w,4)|0;c[(c[j>>2]|0)+1680>>2]=o;o=c[j>>2]|0;p=c[o+1680>>2]|0;if(!p){b=-12;break}r=o+48|0;u=c[r>>2]|0;if((u|0)>0){q=o+44|0;t=c[q>>2]|0;s=0;do{if((t|0)>0){u=c[o+1660>>2]|0;v=c[o+1656>>2]|0;w=0;do{I=$(c[l>>2]|0,c[u+(s<<2)>>2]|0)|0;c[p+(($(t,s)|0)+w<<2)>>2]=(c[v+(w<<2)>>2]|0)+I;w=w+1|0;t=c[q>>2]|0}while((w|0)<(t|0));u=c[r>>2]|0}s=s+1|0}while((s|0)<(u|0))}k=(c[m>>2]|0)-(c[k+13072>>2]|0)|0;v=c[n>>2]|0;c[o+1684>>2]=(c[o+1688>>2]|0)+(v+3<<2);p=v+2|0;if((p|0)>0){m=c[(c[j>>2]|0)+1688>>2]|0;o=0;do{c[m+(($(p,o)|0)<<2)>>2]=-1;c[m+(o<<2)>>2]=-1;o=o+1|0;v=c[n>>2]|0;p=v+2|0}while((o|0)<(p|0))}if((v|0)>-1){m=c[j>>2]|0;j=m+1668|0;p=k<<1;o=(k|0)>0;m=m+1684|0;q=0;while(1){if((v|0)>-1){r=q>>k;t=c[j>>2]|0;s=c[m>>2]|0;u=0;while(1){z=c[t+(($(c[l>>2]|0,r)|0)+(u>>k)<<2)>>2]<>2]=z;v=c[n>>2]|0;if((u|0)<(v|0))u=u+1|0;else break}}if((q|0)<(v|0))q=q+1|0;else break}}if(((c[g+216>>2]|0)-(c[g+212>>2]|0)|0)<0){b=0;break}I=b+(h<<2)+400|0;wd(I);c[I>>2]=c[e>>2];I=0;i=f;return I|0}else b=-12}else b=-1094995529}else b=-1094995529}else b=-1094995529;while(0);wd(e);I=b;i=f;return I|0}function Hc(a,b){a=a|0;b=b|0;var d=0;a=i;i=i+16|0;d=a;c[d>>2]=b;kd(b+1648|0);kd(b+1652|0);kd(b+1656|0);kd(b+1660|0);kd(b+1664|0);kd(b+1668|0);kd(b+1672|0);kd(b+1680|0);kd(b+1676|0);kd(b+1688|0);kd(d);i=a;return}function Ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;d=a+136|0;e=a+2512|0;while(1){f=(c[d>>2]|0)+204|0;g=0;do{h=ad(f,8)|0;g=h+g|0}while((h|0)==255);h=0;do{j=ad(f,8)|0;h=j+h|0}while((j|0)==255);do if((c[e>>2]|0)==39)if((g|0)==256){Jc(a);break}else{cd(f,h<<3);break}else if((g|0)==132){Jc(a);break}else{cd(f,h<<3);break}while(0);f=c[d>>2]|0;if(((c[f+216>>2]|0)-(c[f+212>>2]|0)|0)<=0){a=14;break}if((bd(f+204|0,8)|0)==128){a=14;break}}if((a|0)==14){i=b;return 1}return 0}function Jc(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;e=(c[b+136>>2]|0)+204|0;g=(ad(e,8)|0)&255;f=b+4468|0;h=0;do{if((g|0)==2)cd(e,32);else if((g|0)==1)cd(e,16);else if(!g){a[f>>0]=1;j=0;do{a[b+(h<<4)+j+4420>>0]=ad(e,8)|0;j=j+1|0}while((j|0)!=16)}h=h+1|0}while((h|0)!=3);i=d;return}function Kc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;d=i;f=c[b+52>>2]|0;e=a+60|0;if((f|0)>0){if((c[e>>2]|0)==0?(f=nd(f)|0,c[e>>2]=f,(f|0)==0):0){f=-12;i=d;return f|0}}else c[e>>2]=0;f=a+12|0;c[f>>2]=b;c[a+424>>2]=0;c[a+800>>2]=1;h=a+912|0;g=a+936|0;c[h+0>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[g>>2]=0;c[g+4>>2]=-2147483648;g=a+928|0;c[g>>2]=0;c[g+4>>2]=-2147483648;a=Ga[c[b+76>>2]&3](a)|0;if((a|0)>=0){h=0;i=d;return h|0}kd(e);c[f>>2]=0;h=a;i=d;return h|0}function Lc(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;if(!a){i=b;return 0}e=a+12|0;f=c[e>>2]|0;if((f|0)!=0?(d=c[f+92>>2]|0,(d|0)!=0):0)Ga[d&3](a)|0;c[a+796>>2]=0;kd(a+60|0);c[e>>2]=0;c[a+808>>2]=0;i=b;return 0}function Mc(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0;h=i;if((f|0)<=0){i=h;return 0}j=(e|0)==0;k=0;do{l=d+($(k,g)|0)|0;l=Ka[b&1](a,l)|0;if(!j)c[e+(k<<2)>>2]=l;k=k+1|0}while((k|0)!=(f|0));i=h;return 0}function Nc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0;g=i;if((f|0)<=0){i=g;return 0}h=(e|0)==0;j=0;do{k=Ia[b&1](a,d,j,0)|0;if(!h)c[e+(j<<2)>>2]=k;j=j+1|0}while((j|0)!=(f|0));i=g;return 0}function Oc(b,f,g){b=b|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;h=Cd(c[f+76>>2]|0)|0;b=h+4|0;if(!(a[b>>0]|0)){p=0;i=g;return p|0}k=f+64|0;l=h+5|0;m=f+68|0;n=h+6|0;j=0;while(1){p=($((((e[h+(j<<1)+8>>1]|0)>>>11&15)+8|0)>>>3,c[k>>2]|0)|0)+31&-32;if((j+ -1|0)>>>0<2){p=0-(0-p>>d[l>>0])|0;c[f+(j<<2)+32>>2]=p;o=0-(0-((c[m>>2]|0)+31&-32)>>d[n>>0])|0}else{c[f+(j<<2)+32>>2]=p;o=(c[m>>2]|0)+31&-32}o=td(($(p,o)|0)+32|0)|0;c[f+(j<<2)+304>>2]=o;if(!o){b=-1;f=8;break}c[f+(j<<2)>>2]=c[o+4>>2];j=j+1|0;if((j|0)>=(d[b>>0]|0)){b=0;f=8;break}}if((f|0)==8){i=g;return b|0}return 0}function Pc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;ae(a|0,0,976)|0;e=(b|0)!=0;if(e){c[a+8>>2]=c[b+8>>2];c[a+48>>2]=c[b+12>>2]}else c[a+8>>2]=-1;c[a+100>>2]=0;c[a+104>>2]=1;c[a+888>>2]=0;c[a+892>>2]=1;c[a+896>>2]=0;c[a+900>>2]=1;c[a+476>>2]=1;c[a+816>>2]=1;c[a+820>>2]=1;c[a+220>>2]=0;c[a+224>>2]=1;c[a+136>>2]=-1;c[a+416>>2]=-1;g=a+696|0;c[g>>2]=0;c[g+4>>2]=-2147483648;if((e?(f=c[b+52>>2]|0,(f|0)!=0):0)?(g=nd(f)|0,c[a+60>>2]=g,(g|0)==0):0){g=-12;i=d;return g|0}g=0;i=d;return g|0}function Qc(a){a=a|0;var b=0,c=0;b=i;c=hd(976)|0;if(c){if((Pc(c,a)|0)<0){jd(c);c=0}}else c=0;i=b;return c|0}function Rc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;i=i+80|0;g=f;k=g+0|0;j=e+0|0;h=k+80|0;do{c[k>>2]=c[j>>2];k=k+4|0;j=j+4|0}while((k|0)<(h|0));h=a+12|0;j=c[h>>2]|0;if(!j){k=-22;i=f;return k|0}if(c[j+8>>2]|0){k=-22;i=f;return k|0}c[d>>2]=0;j=c[a+124>>2]|0;k=c[a+128>>2]|0;if(!j){if(k){k=-22;i=f;return k|0}}else{if(!((j|0)>0&(k|0)>0)){k=-22;i=f;return k|0}if((j+128|0)>>>0>=(268435455/((k+128|0)>>>0)|0)>>>0){k=-22;i=f;return k|0}}zd(b);h=c[h>>2]|0;if(((c[h+16>>2]&32|0)==0?(c[e+28>>2]|0)==0:0)?(c[a+808>>2]&1|0)==0:0){k=0;i=f;return k|0}g=Ia[c[h+88>>2]&1](a,b,d,g)|0;if(!(c[d>>2]|0)){zd(b);k=g;i=f;return k|0}else{k=a+424|0;c[k>>2]=(c[k>>2]|0)+1;k=g;i=f;return k|0}return 0}function Sc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=i;if((a|0)>0&(b|0)>0?(a+128|0)>>>0<(268435455/((b+128|0)>>>0)|0)>>>0:0){d=0;i=c;return d|0}d=-22;i=c;return d|0}function Tc(a,b){a=a|0;b=b|0;return 0}function Uc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;e=a+8|0;if(!(c[e>>2]|0)){g=c[a+116>>2]|0;h=a+120|0;j=c[h>>2]|0;if(!((g|0)>0&(j|0)>0)){l=-22;i=f;return l|0}if((g+128|0)>>>0>=(268435455/((j+128|0)>>>0)|0)>>>0){l=-22;i=f;return l|0}j=c[a+136>>2]|0;if((j|0)<0){l=-22;i=f;return l|0}k=b+64|0;l=b+68|0;if((c[k>>2]|0)>=1?(c[l>>2]|0)>=1:0)g=1;else{m=a+792|0;n=0-(0-(c[a+124>>2]|0)>>c[m>>2])|0;c[k>>2]=(g|0)>(n|0)?g:n;k=c[h>>2]|0;g=0-(0-(c[a+128>>2]|0)>>c[m>>2])|0;c[l>>2]=(k|0)>(g|0)?k:g;g=0}c[b+76>>2]=j}else g=1;d=za[c[a+476>>2]&1](a,b,d)|0;if(c[e>>2]|g){n=d;i=f;return n|0}c[b+64>>2]=c[a+116>>2];c[b+68>>2]=c[a+120>>2];n=d;i=f;return n|0}function Vc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=i;c[b+4>>2]=a;a=Uc(a,c[b>>2]|0,d)|0;i=e;return a|0}function Wc(a,b){a=a|0;b=b|0;a=i;b=c[b>>2]|0;if(b)zd(b);i=a;return}function Xc(a){a=a|0;return}function Yc(a,b,c){a=a|0;b=b|0;c=c|0;return}function Zc(a){a=a|0;var b=0,d=0;b=i;d=a+8|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+16|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+64|0;c[d>>2]=-1;c[d+4>>2]=-1;d=a+72|0;c[d>>2]=0;c[d+4>>2]=0;d=a+32|0;c[a>>2]=0;c[d+0>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;i=b;return}function _c(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0;g=a+16|0;c[a+12>>2]=b;c[a+20>>2]=b+e;h=b+1|0;c[g>>2]=h;e=(d[b>>0]|0)<<18;c[a>>2]=e;f=b+2|0;c[g>>2]=f;e=(d[h>>0]|0)<<10|e;c[a>>2]=e;c[g>>2]=b+3;c[a>>2]=(d[f>>0]|0)<<2|e|2;c[a+4>>2]=510;return}function $c(){var b=0,e=0,f=0,g=0,h=0,j=0;b=i;if(!(c[718]|0))e=0;else{i=b;return}while(1)if(e){g=(e&65280|0)==0;a[2880+e>>0]=(g?8:0)-(d[4680+(g?e:e>>>8)>>0]|0);e=e+1|0;if((e|0)==512){e=0;break}else continue}else{a[2880]=9;e=1;continue}while(1){f=e<<1;g=0;do{j=a[4224+(e<<2)+g>>0]|0;h=(g<<7)+f|0;a[(h|1)+3392>>0]=j;a[h+3392>>0]=j;g=g+1|0}while((g|0)!=4);j=(d[4480+e>>0]|0)<<1;a[f+4032>>0]=j;a[f+4033>>0]=j|1;if(e){h=(d[4544+e>>0]|0)<<1;j=128-f|0;a[j+3903>>0]=h;a[j+3902>>0]=h|1;e=e+1|0;if((e|0)==64)break;else continue}else{e=128-f|0;a[e+3903>>0]=1;a[e+3902>>0]=0;e=1;continue}}g=4160|0;f=4608|0;e=g+63|0;do{a[g>>0]=a[f>>0]|0;g=g+1|0;f=f+1|0}while((g|0)<(e|0));c[718]=1;i=b;return}function ad(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=i;f=a+8|0;h=c[f>>2]|0;g=c[a+16>>2]|0;a=(c[a>>2]|0)+(h>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(h&7)>>>(32-b|0);b=h+b|0;c[f>>2]=g>>>0>b>>>0?b:g;i=e;return a|0}function bd(a,b){a=a|0;b=b|0;var e=0,f=0;e=i;f=c[a+8>>2]|0;a=(c[a>>2]|0)+(f>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(f&7)>>>(32-b|0);i=e;return a|0}function cd(a,b){a=a|0;b=b|0;var d=0;d=a+8|0;a=c[a+16>>2]|0;b=(c[d>>2]|0)+b|0;c[d>>2]=a>>>0>b>>>0?b:a;return}function dd(a){a=a|0;var b=0,e=0,f=0;e=a+8|0;f=c[e>>2]|0;b=(d[(c[a>>2]|0)+(f>>>3)>>0]|0)<<(f&7)>>>7&1;c[e>>2]=((f|0)<(c[a+16>>2]|0)&1)+f;return b|0}function ed(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;if(!b){j=0;i=e;return j|0}f=a+8|0;h=c[f>>2]|0;g=c[a+16>>2]|0;j=c[a>>2]|0;a=j+(h>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(h&7);if((b|0)<26){j=h+b|0;c[f>>2]=g>>>0>j>>>0?j:g;j=a>>>(32-b|0);i=e;return j|0}else{k=h+16|0;k=g>>>0>k>>>0?k:g;c[f>>2]=k;h=b+ -16|0;j=j+(k>>>3)|0;j=(Xd(d[j>>0]|d[j+1>>0]<<8|d[j+2>>0]<<16|d[j+3>>0]<<24|0)|0)<<(k&7)>>>(48-b|0);b=k+h|0;c[f>>2]=g>>>0>b>>>0?b:g;j=j|a>>>16<>2]=c[a+0>>2];c[e+4>>2]=c[a+4>>2];c[e+8>>2]=c[a+8>>2];c[e+12>>2]=c[a+12>>2];c[e+16>>2]=c[a+16>>2];e=ed(e,32)|0;f=e>>>0>65535;e=f?e>>>16:e;f=f?16:0;if(e&65280){f=f|8;e=e>>>8}j=31-f-(d[4680+e>>0]|0)|0;g=a+8|0;f=c[g>>2]|0;e=0-f|0;h=(c[a+16>>2]|0)-f|0;if((j|0)<(e|0)){h=e;h=h+f|0;c[g>>2]=h;j=j+1|0;j=ed(a,j)|0;j=j+ -1|0;i=b;return j|0}h=(h|0)<(j|0)?h:j;h=h+f|0;c[g>>2]=h;j=j+1|0;j=ed(a,j)|0;j=j+ -1|0;i=b;return j|0}function gd(a){a=a|0;var b=0;b=i;a=fd(a)|0;if(!(a&1)){a=0-(a>>>1)|0;i=b;return a|0}else{a=(a+1|0)>>>1;i=b;return a|0}return 0}function hd(a){a=a|0;var b=0,d=0,e=0;b=i;d=c[1168]|0;if((d+ -32|0)>>>0>=a>>>0){e=Sd(a)|0;if((e|0)==0&(a|0)==0)if((d|0)==32)e=0;else e=Sd(1)|0}else e=0;i=b;return e|0}function id(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;f=$(d,b)|0;if((d|b)>>>0>65535&(d|0)!=0?((f>>>0)/(d>>>0)|0|0)!=(b|0):0){Td(a);d=0;i=e;return d|0}if(((c[1168]|0)+ -32|0)>>>0>>0)b=0;else b=Ud(a,((f|0)==0&1)+f|0)|0;if((b|0)!=0|(f|0)==0){d=b;i=e;return d|0}Td(a);d=0;i=e;return d|0}function jd(a){a=a|0;var b=0;b=i;Td(a);i=b;return}function kd(a){a=a|0;var b=0;b=i;Td(c[a>>2]|0);c[a>>2]=0;i=b;return}function ld(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;if(((d|0)!=0?(2147483647/(d>>>0)|0)>>>0>b>>>0:0)?(f=$(d,b)|0,((c[1168]|0)+ -32|0)>>>0>=f>>>0):0)a=Ud(a,((f|0)==0&1)+f|0)|0;else a=0;i=e;return a|0}function md(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=i;e=id(c[a>>2]|0,b,d)|0;c[a>>2]=e;i=f;return((e|0)!=0|(b|0)==0|(d|0)==0?0:-12)|0}function nd(a){a=a|0;var b=0,c=0;c=i;b=hd(a)|0;if(b)ae(b|0,0,a|0)|0;i=c;return b|0}function od(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;if((c[b>>2]|0)>>>0>d>>>0){i=e;return}f=((d*17|0)>>>4)+32|0;d=f>>>0>d>>>0?f:d;Td(c[a>>2]|0);f=hd(d)|0;c[a>>2]=f;c[b>>2]=(f|0)==0?0:d;i=e;return}function pd(a,b){a=a|0;b=b|0;var c=0;c=i;if((b|0)!=0?(2147483647/(b>>>0)|0)>>>0>a>>>0:0)b=hd($(b,a)|0)|0;else b=0;i=c;return b|0}function qd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;if(((b|0)!=0?(2147483647/(b>>>0)|0)>>>0>a>>>0:0)?(e=$(b,a)|0,d=hd(e)|0,(d|0)!=0):0)ae(d|0,0,e|0)|0;else d=0;i=c;return d|0}function rd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0;g=i;i=i+16|0;h=g;j=nd(24)|0;c[h>>2]=j;if(!j){f=0;i=g;return f|0}c[j>>2]=a;c[j+4>>2]=b;c[j+12>>2]=(d|0)!=0?d:7;c[j+16>>2]=e;c[j+8>>2]=1;if(f&1){f=(c[h>>2]|0)+20|0;c[f>>2]=c[f>>2]|1}j=nd(12)|0;if(!j){kd(h);f=0;i=g;return f|0}else{c[j>>2]=c[h>>2];c[j+4>>2]=a;c[j+8>>2]=b;f=j;i=g;return f|0}return 0}function sd(a,b){a=a|0;b=b|0;a=i;jd(b);i=a;return}function td(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;e=hd(a)|0;c[d>>2]=e;if(e){a=rd(e,a,7,0,0)|0;if(!a){kd(d);a=0}}else a=0;i=b;return a|0}function ud(a){a=a|0;var b=0,d=0;b=i;d=td(a)|0;if(!d){d=0;i=b;return d|0}ae(c[d+4>>2]|0,0,a|0)|0;i=b;return d|0}function vd(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;e=b;d=nd(12)|0;if(!d){e=0;i=b;return e|0}c[d+0>>2]=c[a+0>>2];c[d+4>>2]=c[a+4>>2];c[d+8>>2]=c[a+8>>2];f=(c[a>>2]|0)+8|0;a=c[f>>2]|0;c[f>>2]=a+1;c[e>>2]=a+1;e=d;i=b;return e|0}function wd(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;e=b+4|0;d=b;if(!a){i=b;return}f=c[a>>2]|0;if(!f){i=b;return}f=c[f>>2]|0;c[d>>2]=f;kd(a);a=f+8|0;f=c[a>>2]|0;c[a>>2]=f+ -1;c[e>>2]=f+ -1;if(c[e>>2]|0){i=b;return}f=c[d>>2]|0;Ea[c[f+12>>2]&7](c[f+16>>2]|0,c[f>>2]|0);kd(d);i=b;return}function xd(){var a=0,b=0,d=0;a=i;b=nd(400)|0;if(!b){b=0;i=a;return b|0}ae(b|0,0,400)|0;d=b+136|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+144|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+128|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+360|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+376|0;c[d>>2]=0;c[d+4>>2]=0;d=b+368|0;c[d>>2]=-1;c[d+4>>2]=-1;c[b+392>>2]=-1;c[b+80>>2]=1;c[b+120>>2]=0;c[b+124>>2]=1;c[b+76>>2]=-1;c[b+344>>2]=2;c[b+348>>2]=2;c[b+352>>2]=2;c[b+340>>2]=0;c[b+356>>2]=0;i=a;return b|0}function yd(a){a=a|0;var b=0,d=0;b=i;if((a|0)!=0?(d=c[a>>2]|0,(d|0)!=0):0){zd(d);kd(a)}i=b;return}function zd(a){a=a|0;var b=0,d=0;b=i;wd(a+304|0);wd(a+308|0);wd(a+312|0);wd(a+316|0);wd(a+320|0);wd(a+324|0);wd(a+328|0);wd(a+332|0);ae(a|0,0,400)|0;d=a+136|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+144|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+128|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+360|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+376|0;c[d>>2]=0;c[d+4>>2]=0;d=a+368|0;c[d>>2]=-1;c[d+4>>2]=-1;c[a+392>>2]=-1;c[a+80>>2]=1;c[a+120>>2]=0;c[a+124>>2]=1;c[a+76>>2]=-1;c[a+344>>2]=2;c[a+348>>2]=2;c[a+352>>2]=2;c[a+340>>2]=0;c[a+356>>2]=0;i=b;return}function Ad(a,b){a=a|0;b=b|0;var d=0;d=i;ce(a|0,b|0,400)|0;ae(b|0,0,400)|0;a=b+136|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+144|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+128|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+360|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+376|0;c[a>>2]=0;c[a+4>>2]=0;a=b+368|0;c[a>>2]=-1;c[a+4>>2]=-1;c[b+392>>2]=-1;c[b+80>>2]=1;c[b+120>>2]=0;c[b+124>>2]=1;c[b+76>>2]=-1;c[b+344>>2]=2;c[b+348>>2]=2;c[b+352>>2]=2;c[b+340>>2]=0;c[b+356>>2]=0;i=d;return}function Bd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;c[a+76>>2]=c[b+76>>2];c[a+64>>2]=c[b+64>>2];c[a+68>>2]=c[b+68>>2];c[a+388>>2]=c[b+388>>2];j=b+296|0;h=c[j+4>>2]|0;f=a+296|0;c[f>>2]=c[j>>2];c[f+4>>2]=h;c[a+72>>2]=c[b+72>>2];f=c[b+304>>2]|0;if(!f)sa();else{e=f;g=0}while(1){if((e|0)!=0?(j=vd(e)|0,c[a+(g<<2)+304>>2]=j,(j|0)==0):0){e=5;break}g=g+1|0;if(g>>>0>=8){e=8;break}e=c[b+(g<<2)+304>>2]|0}if((e|0)==5){zd(a);j=-12;i=d;return j|0}else if((e|0)==8){c[a+0>>2]=c[b+0>>2];c[a+4>>2]=c[b+4>>2];c[a+8>>2]=c[b+8>>2];c[a+12>>2]=c[b+12>>2];c[a+16>>2]=c[b+16>>2];c[a+20>>2]=c[b+20>>2];c[a+24>>2]=c[b+24>>2];c[a+28>>2]=c[b+28>>2];j=a+32|0;h=b+32|0;c[j+0>>2]=c[h+0>>2];c[j+4>>2]=c[h+4>>2];c[j+8>>2]=c[h+8>>2];c[j+12>>2]=c[h+12>>2];c[j+16>>2]=c[h+16>>2];c[j+20>>2]=c[h+20>>2];c[j+24>>2]=c[h+24>>2];c[j+28>>2]=c[h+28>>2];j=0;i=d;return j|0}return 0}function Cd(a){a=a|0;var b=0,d=0,e=0,f=0;d=i;e=0;while(1){f=e+1|0;if((c[4936+(e*24|0)>>2]|0)==(a|0))break;if(f>>>0<4)e=f;else{e=0;b=5;break}}if((b|0)==5){i=d;return e|0}f=4940+(e*24|0)|0;i=d;return f|0}function Dd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;g=(c[b+16>>2]|0)==0?1:3;if((g|0)>(e|0)){b=c[b>>2]|0;c[d>>2]=c[b+(e<<2)+32>>2];b=c[b+(e<<2)>>2]|0;i=f;return b|0}if((a[b+20>>0]|0)!=0&(g|0)==(e|0)){b=c[b+4>>2]|0;c[d>>2]=c[b+32>>2];b=c[b>>2]|0;i=f;return b|0}else{c[d>>2]=0;b=0;i=f;return b|0}return 0}function Ed(b,e){b=b|0;e=e|0;var f=0,g=0,h=0;f=i;if(!(c[b>>2]|0)){h=-1;i=f;return h|0}c[e>>2]=c[b+8>>2];c[e+4>>2]=c[b+12>>2];c[e+8>>2]=c[b+16>>2];g=b+22|0;if(!(a[b+20>>0]|0))h=0;else h=(a[g>>0]|0)==0;c[e+12>>2]=h&1;c[e+24>>2]=d[b+24>>0];c[e+28>>2]=d[g>>0];c[e+32>>2]=d[b+23>>0];c[e+16>>2]=c[b+28>>2];c[e+20>>2]=d[b+21>>0];h=0;i=f;return h|0}function Fd(f,g){f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;k=i;j=c[f+8>>2]|0;h=f+44|0;o=c[h>>2]|0;if(o>>>0>=(c[f+12>>2]|0)>>>0){x=-1;i=k;return x|0}n=(c[f+56>>2]|0)+($(c[f+72>>2]|0,o)|0)|0;l=f+40|0;m=(d[l>>0]|0)+3|0;p=c[f+16>>2]|0;if((p|0)==1){v=o>>1;q=(v|0)%8|0;w=f+88|0;u=c[w>>2]|0;t=f+96|0;p=f+160|0;s=c[p>>2]|0;x=f+21|0;r=d[x>>0]|0;if(!(o&1)){Gd(u,t,j,q,s,r,0);Gd(c[f+92>>2]|0,f+128|0,j,q,c[p>>2]|0,d[x>>0]|0,0)}else{Gd(u,t,j,q,s,r,1);Gd(c[f+92>>2]|0,f+128|0,j,q,c[p>>2]|0,d[x>>0]|0,1);u=(q+5|0)%8|0;t=v+5|0;v=c[f+52>>2]|0;v=(t|0)<(v|0)?t:v+ -1|0;t=(c[f+60>>2]|0)+($(v,c[f+76>>2]|0)|0)|0;v=(c[f+64>>2]|0)+($(c[f+80>>2]|0,v)|0)|0;x=f+48|0;ce(c[f+(u<<2)+96>>2]|0,t|0,c[x>>2]<<1|0)|0;ce(c[f+(u<<2)+128>>2]|0,v|0,c[x>>2]<<1|0)|0}Ba[c[f+212>>2]&7](f+164|0,g,n,c[w>>2]|0,c[f+92>>2]|0,j,m)}else if(!p)Ba[c[f+212>>2]&7](f+164|0,g,n,0,0,j,m);else if((p|0)==3){w=(c[f+60>>2]|0)+($(c[f+76>>2]|0,o)|0)|0;x=(c[f+64>>2]|0)+($(c[f+80>>2]|0,o)|0)|0;Ba[c[f+212>>2]&7](f+164|0,g,n,w,x,j,m)}else if((p|0)==2){x=(c[f+60>>2]|0)+($(c[f+76>>2]|0,o)|0)|0;u=(c[f+64>>2]|0)+($(c[f+80>>2]|0,o)|0)|0;w=f+88|0;v=f+21|0;Hd(c[w>>2]|0,x,j,d[v>>0]|0);x=f+92|0;Hd(c[x>>2]|0,u,j,d[v>>0]|0);Ba[c[f+212>>2]&7](f+164|0,g,n,c[w>>2]|0,c[x>>2]|0,j,m)}else{x=-1;i=k;return x|0}a:do if(!(a[f+22>>0]|0)){if(a[l>>0]|0){if(!(a[f+20>>0]|0)){if((j|0)<=0)break;f=g+3|0;g=0;while(1){a[f>>0]=-1;g=g+1|0;if((g|0)==(j|0))break a;else f=f+4|0}}l=(c[f+68>>2]|0)+($(c[f+84>>2]|0,o)|0)|0;q=g+3|0;if((c[f+204>>2]|0)==8){if((j|0)>0){m=0;while(1){a[q>>0]=b[l+(m<<1)>>1];m=m+1|0;if((m|0)==(j|0))break;else q=q+4|0}}}else{m=c[f+172>>2]|0;n=c[f+168>>2]|0;o=c[f+164>>2]|0;if((j|0)>0){p=0;while(1){a[q>>0]=($(e[l+(p<<1)>>1]|0,m)|0)+n>>o;p=p+1|0;if((p|0)==(j|0))break;else q=q+4|0}}}if(a[f+24>>0]|0){if(!(c[1264]|0)){c[1264]=1;f=1;do{c[5064+(f<<2)>>2]=(((f|0)/2|0)+16711808|0)/(f|0)|0;f=f+1|0}while((f|0)!=256)}if((j|0)>0){f=0;while(1){m=a[g+3>>0]|0;if(!(m<<24>>24)){a[g>>0]=-1;a[g+1>>0]=-1;a[g+2>>0]=-1}else{l=c[5064+((m&255)<<2)>>2]|0;n=a[g>>0]|0;if((n&255)<(m&255))n=(($(n&255,l)|0)+32768|0)>>>16&255;else n=-1;a[g>>0]=n;n=g+1|0;o=a[n>>0]|0;if((o&255)<(m&255))o=(($(o&255,l)|0)+32768|0)>>>16&255;else o=-1;a[n>>0]=o;n=g+2|0;o=a[n>>0]|0;if((o&255)<(m&255))l=(($(o&255,l)|0)+32768|0)>>>16&255;else l=-1;a[n>>0]=l}f=f+1|0;if((f|0)==(j|0))break;else g=g+4|0}}}}}else{n=(c[f+68>>2]|0)+($(c[f+84>>2]|0,o)|0)|0;p=c[f+204>>2]|0;o=1<0;if(r){f=g;q=0;while(1){w=e[n+(q<<1)>>1]|0;a[f>>0]=($(d[f>>0]|0,w)|0)+o>>p;x=f+1|0;a[x>>0]=($(d[x>>0]|0,w)|0)+o>>p;x=f+2|0;a[x>>0]=($(d[x>>0]|0,w)|0)+o>>p;q=q+1|0;if((q|0)==(j|0))break;else f=f+m|0}}if(!((a[l>>0]|0)==0|r^1)){f=g+3|0;g=0;while(1){a[f>>0]=-1;g=g+1|0;if((g|0)==(j|0))break;else f=f+4|0}}}while(0);c[h>>2]=(c[h>>2]|0)+1;x=0;i=k;return x|0}function Gd(a,d,f,g,h,j,k){a=a|0;d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;l=i;m=c[d+((g+5&7)<<2)>>2]|0;n=c[d+((g+6&7)<<2)>>2]|0;r=c[d+((g+7&7)<<2)>>2]|0;q=c[d+((g&7)<<2)>>2]|0;p=c[d+((g+1&7)<<2)>>2]|0;o=c[d+((g+2&7)<<2)>>2]|0;g=c[d+((g+3&7)<<2)>>2]|0;s=j+ -8|0;d=(f+1|0)/2|0;t=(f|0)>0;if(!k){if(t){k=0;do{y=($(e[n+(k<<1)>>1]|0,-6)|0)+(e[m+(k<<1)>>1]<<1)|0;y=y+((e[r+(k<<1)>>1]|0)*18|0)+((e[q+(k<<1)>>1]|0)*57|0)+($(e[p+(k<<1)>>1]|0,-10)|0)|0;b[h+(k+3<<1)>>1]=y+(e[o+(k<<1)>>1]<<2)-(e[g+(k<<1)>>1]|0)>>s;k=k+1|0}while((k|0)<(d|0))}}else if(t){k=0;do{y=(e[n+(k<<1)>>1]<<2)-(e[m+(k<<1)>>1]|0)+($(e[r+(k<<1)>>1]|0,-10)|0)|0;y=y+((e[q+(k<<1)>>1]|0)*57|0)+((e[p+(k<<1)>>1]|0)*18|0)+($(e[o+(k<<1)>>1]|0,-6)|0)|0;b[h+(k+3<<1)>>1]=y+(e[g+(k<<1)>>1]<<1)>>s;k=k+1|0}while((k|0)<(d|0))}r=h+6|0;m=b[r>>1]|0;b[h>>1]=m;u=h+2|0;b[u>>1]=m;t=h+4|0;b[t>>1]=m;m=b[h+(d+2<<1)>>1]|0;b[h+(d+3<<1)>>1]=m;b[h+(d+4<<1)>>1]=m;b[h+(d+5<<1)>>1]=m;b[h+(d+6<<1)>>1]=m;m=(1<>1]|0;u=b[u>>1]|0;t=b[t>>1]|0;d=b[r>>1]|0;k=b[h+8>>1]|0;g=b[h+10>>1]|0;if((f|0)>1){p=f+ -2|0;o=p>>>1;q=o<<1;w=a;while(1){v=b[r+6>>1]|0;x=d*57|0;y=(g<<2)+n+($(k,-10)|0)+x+(t*18|0)+($(u,-6)|0)+(s<<1)-v>>j;if((y|0)<0)y=0;else y=((y|0)>(m|0)?m:y)&65535;b[w>>1]=y;s=($(g,-6)|0)+n+(k*18|0)+x+($(t,-10)|0)-s+(u<<2)+(v<<1)>>j;if((s|0)<0)s=0;else s=((s|0)>(m|0)?m:s)&65535;b[w+2>>1]=s;f=f+ -2|0;if((f|0)<=1)break;else{A=g;z=k;x=d;y=t;s=u;g=v;w=w+4|0;r=r+2|0;k=A;d=z;t=x;u=y}}s=u;u=t;t=d;d=k;k=g;g=v;a=a+(q+2<<1)|0;f=p-q|0;r=h+(o+4<<1)|0}if(!f){i=l;return}h=(g<<2)+n+($(k,-10)|0)+(d*57|0)+(t*18|0)+($(u,-6)|0)+(s<<1)-(b[r+6>>1]|0)>>j;if((h|0)<0)h=0;else h=((h|0)>(m|0)?m:h)&65535;b[a>>1]=h;i=l;return}function Hd(a,c,d,f){a=a|0;c=c|0;d=d|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;g=i;s=(d+1|0)/2|0;o=s<<1;h=hd(o+14|0)|0;j=h+6|0;ce(j|0,c|0,o|0)|0;o=b[c>>1]|0;b[h>>1]=o;b[h+2>>1]=o;b[h+4>>1]=o;c=b[c+(s+ -1<<1)>>1]|0;b[h+(s+3<<1)>>1]=c;b[h+(s+4<<1)>>1]=c;b[h+(s+5<<1)>>1]=c;b[h+(s+6<<1)>>1]=c;c=(1<>1]|0;o=e[h+2>>1]|0;q=e[h+4>>1]|0;p=e[j>>1]|0;n=e[h+8>>1]|0;m=e[h+10>>1]|0;if((d|0)>1){k=d+ -2|0;l=k>>>1;f=l+1|0;r=p;p=n;n=m;t=a;u=j;while(1){m=e[u+6>>1]|0;v=r*57|0;w=(n<<2)+32+($(p,-10)|0)+v+(q*18|0)+($(o,-6)|0)+(s<<1)-m>>6;if((w|0)<0)w=0;else w=((w|0)>(c|0)?c:w)&65535;b[t>>1]=w;s=($(n,-6)|0)+32+(p*18|0)+v+($(q,-10)|0)-s+(o<<2)+(m<<1)>>6;if((s|0)<0)s=0;else s=((s|0)>(c|0)?c:s)&65535;b[t+2>>1]=s;d=d+ -2|0;if((d|0)<=1)break;else{y=n;x=p;v=r;w=q;s=o;n=m;t=t+4|0;u=u+2|0;p=y;r=x;q=v;o=w}}d=l<<1;l=o;o=q;q=r;a=a+(d+2<<1)|0;d=k-d|0;j=j+(f<<1)|0}else l=s;if(!d){jd(h);i=g;return}j=(m<<2)+32+($(n,-10)|0)+(p*57|0)+(q*18|0)+($(o,-6)|0)+(l<<1)-(e[j+6>>1]|0)>>6;if((j|0)<0)j=0;else j=((j|0)>(c|0)?c:j)&65535;b[a>>1]=j;jd(h);i=g;return}function Id(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0,t=0.0,u=0,v=0,w=0,x=0,y=0,z=0.0,A=0.0,B=0.0;f=i;if(!(c[b>>2]|0)){w=-1;i=f;return w|0}g=b+44|0;if((c[g>>2]|0)>-1|e>>>0>1){w=-1;i=f;return w|0}a[b+40>>0]=(e|0)==1&1;k=b+41|0;a[k>>0]=0;c[b+56>>2]=Dd(b,b+72|0,0)|0;e=b+16|0;if(!(c[e>>2]|0))m=1;else{c[b+60>>2]=Dd(b,b+76|0,1)|0;c[b+64>>2]=Dd(b,b+80|0,2)|0;m=3}if(!(a[b+20>>0]|0))c[b+68>>2]=0;else c[b+68>>2]=Dd(b,b+84|0,m)|0;if(((c[e>>2]|0)+ -1|0)>>>0<2?(w=b+8|0,v=c[w>>2]|0,l=b+48|0,c[l>>2]=(v+1|0)/2|0,j=b+52|0,c[j>>2]=((c[b+12>>2]|0)+1|0)/2|0,c[b+88>>2]=hd(v<<1)|0,c[b+92>>2]=hd(c[w>>2]<<1)|0,(c[e>>2]|0)==1):0){m=0;o=c[l>>2]<<1;do{c[b+(m<<2)+96>>2]=hd(o)|0;c[b+(m<<2)+128>>2]=hd(c[l>>2]<<1)|0;m=m+1|0;o=c[l>>2]<<1}while((m|0)!=8);c[b+160>>2]=hd(o+14|0)|0;m=b+60|0;o=b+76|0;s=b+64|0;u=b+80|0;v=0;do{w=(v|0)>4?v+ -8|0:v;if((w|0)<0)w=0;else{x=c[j>>2]|0;w=(w|0)<(x|0)?w:x+ -1|0}y=(c[m>>2]|0)+($(c[o>>2]|0,w)|0)|0;x=(c[s>>2]|0)+($(c[u>>2]|0,w)|0)|0;ce(c[b+(v<<2)+96>>2]|0,y|0,c[l>>2]<<1|0)|0;ce(c[b+(v<<2)+128>>2]|0,x|0,c[l>>2]<<1|0)|0;v=v+1|0}while((v|0)!=8)}j=d[b+21>>0]|0;y=(a[k>>0]|0)!=0?16:8;m=b+28|0;s=c[m>>2]|0;l=a[b+23>>0]|0;k=l&255;o=30-y|0;n=+((1<>24!=0;if(l){y=j+ -8|0;q=n/+(224<>2]=ra(+(q*B*2.0))|0;z=1.0-t;A=z-r;c[b+188>>2]=ra(+(q*(t*2.0*z/A)))|0;c[b+192>>2]=ra(+(q*(r*2.0*B/A)))|0;c[b+196>>2]=ra(+(q*z*2.0))|0}h=ra(+p)|0;c[b+172>>2]=h;c[b+164>>2]=o;s=1<>2]=s;c[b+200>>2]=1<>2]=y;y=$(y,-16<>2]=y+(c[o>>2]|0)}else{c[b+176>>2]=h;c[b+180>>2]=s}c[b+204>>2]=j;c[b+208>>2]=k;if(!(c[e>>2]|0))c[b+212>>2]=7;else c[b+212>>2]=c[5032+(c[m>>2]<<2)>>2];c[g>>2]=0;y=0;i=f;return y|0}function Jd(){var a=0,b=0;a=i;b=nd(216)|0;if(!b)b=0;i=a;return b|0}function Kd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+48|0;m=f+36|0;l=f;if((e|0)<6){u=-1;i=f;return u|0}if((a[d>>0]|0)!=66){u=-1;i=f;return u|0}if((a[d+1>>0]|0)!=80){u=-1;i=f;return u|0}if((a[d+2>>0]|0)!=71){u=-1;i=f;return u|0}if((a[d+3>>0]|0)!=-5){u=-1;i=f;return u|0}t=a[d+4>>0]|0;u=t&255;n=u>>>5;k=l+8|0;c[k>>2]=n;if(t<<24>>24<0){u=-1;i=f;return u|0}t=(u&15)+8|0;a[l+13>>0]=t;if((t&255)>>>0>14){u=-1;i=f;return u|0}q=a[d+5>>0]|0;j=q&255;p=j>>>4;h=l+20|0;c[h>>2]=p;o=j&8;r=j>>>2&1;g=l+16|0;a[g>>0]=j>>>1&1;j=l+12|0;a[j>>0]=0;s=l+14|0;a[s>>0]=0;t=l+15|0;a[t>>0]=0;if(!(u&16))if(!r)r=0;else{a[j>>0]=1;a[s>>0]=1;r=1}else{a[j>>0]=1;a[t>>0]=r;r=0}if((q&255)>79){u=-1;i=f;return u|0}if(!((n|0)!=0|(p|0)==0)){u=-1;i=f;return u|0}if(r<<24>>24!=0&(n|0)==0){u=-1;i=f;return u|0}n=Nd(l,d+6|0,e+ -6|0)|0;if((n|0)<0){u=-1;i=f;return u|0}n=n+6|0;p=l+4|0;q=Nd(p,d+n|0,e-n|0)|0;if((q|0)<0){u=-1;i=f;return u|0}q=q+n|0;if(!(c[l>>2]|0)){u=-1;i=f;return u|0}if(!(c[p>>2]|0)){u=-1;i=f;return u|0}n=l+24|0;r=Nd(n,d+q|0,e-q|0)|0;if((r|0)<0){u=-1;i=f;return u|0}s=r+q|0;c[m>>2]=0;q=(o|0)!=0;do if(q){o=Nd(m,d+s|0,e-s|0)|0;if((o|0)<0){u=-1;i=f;return u|0}else{s=o+s|0;break}}while(0);o=l+28|0;c[o>>2]=0;do if(a[j>>0]|0){r=Nd(o,d+s|0,e-s|0)|0;if((r|0)<0){u=-1;i=f;return u|0}else{s=r+s|0;break}}while(0);c[l+32>>2]=0;do if(q){m=(c[m>>2]|0)+s|0;if((m|0)>(e|0))b=-1;else break;i=f;return b|0}else m=s;while(0);if((m|0)<0){u=m;i=f;return u|0}l=c[l>>2]|0;p=c[p>>2]|0;k=c[k>>2]|0;t=c[j>>2]|0;j=t&255;u=c[h>>2]|0;s=(t&65535)>>>8;h=s&65535;r=b+8|0;c[r>>2]=l;q=b+12|0;c[q>>2]=p;c[b+16>>2]=k;a[b+20>>0]=j;a[b+24>>0]=t>>>24;a[b+22>>0]=t>>>16;a[b+23>>0]=a[g>>0]|0;c[b+28>>2]=u;a[b+21>>0]=s;g=b+36|0;c[g>>2]=0;s=c[n>>2]|0;n=s+m|0;a:do if(n>>>0>e>>>0)d=b;else{m=Ld(d+m|0,s,l,p,k,h)|0;c[b>>2]=m;if(!m){d=b;break}if((c[m+64>>2]|0)<(c[r>>2]|0)){d=b;break}if((c[m+68>>2]|0)<(c[q>>2]|0)){d=b;break}switch(c[m+76>>2]|0){case 5:case 58:{if((k|0)!=3){d=b;break a}break};case 8:case 32:{if(k){d=b;break a}break};case 0:case 54:{if((k|0)!=1){d=b;break a}break};case 4:case 56:{if((k|0)!=2){d=b;break a}break};default:{d=b;break a}}if(j<<24>>24){j=c[o>>2]|0;if((j+n|0)>>>0>e>>>0){d=b;break}u=Ld(d+n|0,j,l,p,0,h)|0;c[b+4>>2]=u;if(!u){d=b;break}}c[b+44>>2]=-1;u=0;i=f;return u|0}while(0);if(c[d>>2]|0)yd(d);b=b+4|0;if(c[b>>2]|0)yd(b);c[g>>2]=0;u=-1;i=f;return u|0}function Ld(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;k=i;i=i+96|0;n=k+88|0;o=k;l=k+84|0;q=k+80|0;p=Nd(q,b,d)|0;if((p|0)<0){b=0;i=k;return b|0}r=d-p|0;s=c[q>>2]|0;if(s>>>0>r>>>0){b=0;i=k;return b|0}d=s+10|0;q=hd(d)|0;a[q>>0]=g;a[q+1>>0]=e>>>24;a[q+2>>0]=e>>>16;a[q+3>>0]=e>>>8;a[q+4>>0]=e;a[q+5>>0]=f>>>24;a[q+6>>0]=f>>>16;a[q+7>>0]=f>>>8;a[q+8>>0]=f;a[q+9>>0]=h+248;ce(q+10|0,b+p|0,s|0)|0;g=b+(s+p)|0;r=r-s|0;p=hd((d<<1)+10-s+r|0)|0;a[p>>0]=0;a[p+1>>0]=0;a[p+2>>0]=0;a[p+3>>0]=1;a[p+4>>0]=96;a[p+5>>0]=1;if((d|0)>0){f=0;s=6;while(1){e=f+1|0;h=a[q+f>>0]|0;if((e|0)<(d|0)&h<<24>>24==0)if(!(a[q+e>>0]|0)){a[p+s>>0]=0;a[p+(s+1)>>0]=0;a[p+(s+2)>>0]=3;e=f+2|0;s=s+3|0}else{h=0;j=7}else j=7;if((j|0)==7){j=0;a[p+s>>0]=h;s=s+1|0}if((e|0)<(d|0))f=e;else break}if(!s){s=0;j=11}else j=10}else{s=6;j=10}if((j|0)==10)if(!(a[p+(s+ -1)>>0]|0))j=11;if((j|0)==11){a[p+s>>0]=-128;s=s+1|0}jd(q);a[p+s>>0]=0;a[p+(s+1)>>0]=0;a[p+(s+2)>>0]=0;b=s+4|0;a[p+(s+3)>>0]=1;ce(p+b|0,g|0,r|0)|0;r=b+r|0;Zc(o);g=Qc(1416)|0;if(!g)wa(1);if(c[358]&8){b=g+84|0;c[b>>2]=c[b>>2]|65536}b=g+688|0;c[b>>2]=c[b>>2]|1;if((Kc(g,1416,0)|0)<0)wa(1);s=xd()|0;c[l>>2]=s;if(!s){b=0;i=k;return b|0}q=o+28|0;c[q>>2]=r;d=o+24|0;c[d>>2]=p;if((r|0)>0){r=s;s=0;while(1){r=Rc(g,r,n,o)|0;if((r|0)<0){j=26;break}m=((c[n>>2]|0)!=0&1)+s|0;s=c[d>>2]|0;e=c[q>>2]|0;if(s){e=e-r|0;c[q>>2]=e;c[d>>2]=s+r}if((e|0)<=0)break;r=c[l>>2]|0;s=m}if((j|0)==26)wa(1);Lc(g)|0;jd(g);jd(p);if(m){b=c[l>>2]|0;i=k;return b|0}}else{Lc(g)|0;jd(g);jd(p)}yd(l);b=0;i=k;return b|0}function Md(a){a=a|0;var b=0,d=0;b=i;jd(c[a+88>>2]|0);jd(c[a+92>>2]|0);d=0;do{jd(c[a+(d<<2)+96>>2]|0);jd(c[a+(d<<2)+128>>2]|0);d=d+1|0}while((d|0)!=8);jd(c[a+160>>2]|0);if(c[a>>2]|0)yd(a);d=a+4|0;if(!(c[d>>2]|0)){jd(a);i=b;return}yd(d);jd(a);i=b;return}function Nd(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0;g=i;if((f|0)<1){l=-1;i=g;return l|0}k=e+1|0;l=a[e>>0]|0;j=l&255;if(l<<24>>24<=-1){if(l<<24>>24==-128){l=-1;i=g;return l|0}j=j&127;while(1){if((f|0)<2){b=-1;h=10;break}l=k;k=k+1|0;l=d[l>>0]|0;j=l&127|j<<7;if(!(l&128))break;else f=f+ -1|0}if((h|0)==10){i=g;return b|0}c[b>>2]=j;h=k-e|0;if((h|0)<0){l=h;i=g;return l|0}}else{c[b>>2]=j;h=1}l=j>>>0>1073741823?-1:h;i=g;return l|0}function Od(d,f,g,h,j,k,l){d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0;j=i;if((c[d+40>>2]|0)==8?(c[d+44>>2]|0)==0:0){if((k|0)>0)h=0;else{i=j;return}while(1){o=b[g+(h<<1)>>1]&255;a[f>>0]=o;a[f+1>>0]=o;a[f+2>>0]=o;h=h+1|0;if((h|0)==(k|0))break;else f=f+l|0}i=j;return}m=c[d+12>>2]|0;h=c[d+16>>2]|0;d=c[d>>2]|0;if((k|0)>0)n=0;else{i=j;return}while(1){o=($(e[g+(n<<1)>>1]|0,m)|0)+h>>d;if((o|0)<0)o=0;else o=(o|0)>255?-1:o&255;a[f>>0]=o;a[f+1>>0]=o;a[f+2>>0]=o;n=n+1|0;if((n|0)==(k|0))break;else f=f+l|0}i=j;return}function Pd(b,d,f,g,h,j,k){b=b|0;d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;q=i;s=c[b+20>>2]|0;n=c[b+24>>2]|0;o=c[b+28>>2]|0;l=c[b+32>>2]|0;p=c[b+12>>2]|0;r=c[b+16>>2]|0;m=c[b>>2]|0;b=c[b+36>>2]|0;if((j|0)>0)t=0;else{i=q;return}while(1){v=$(e[f+(t<<1)>>1]|0,p)|0;u=(e[g+(t<<1)>>1]|0)-b|0;w=(e[h+(t<<1)>>1]|0)-b|0;v=v+r|0;x=v+($(w,s)|0)>>m;if((x|0)<0)x=0;else x=(x|0)>255?-1:x&255;a[d>>0]=x;w=v-($(u,n)|0)-($(w,o)|0)>>m;if((w|0)<0)w=0;else w=(w|0)>255?-1:w&255;a[d+1>>0]=w;u=v+($(u,l)|0)>>m;if((u|0)<0)u=0;else u=(u|0)>255?-1:u&255;a[d+2>>0]=u;t=t+1|0;if((t|0)==(j|0))break;else d=d+k|0}i=q;return}function Qd(d,f,g,h,j,k,l){d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0;m=i;if((c[d+40>>2]|0)==8?(c[d+44>>2]|0)==0:0){if((k|0)>0)n=0;else{i=m;return}while(1){a[f>>0]=b[j+(n<<1)>>1];a[f+1>>0]=b[g+(n<<1)>>1];a[f+2>>0]=b[h+(n<<1)>>1];n=n+1|0;if((n|0)==(k|0))break;else f=f+l|0}i=m;return}o=c[d+12>>2]|0;n=c[d+16>>2]|0;d=c[d>>2]|0;if((k|0)>0)p=0;else{i=m;return}while(1){q=($(e[j+(p<<1)>>1]|0,o)|0)+n>>d;if((q|0)<0)q=0;else q=(q|0)>255?-1:q&255;a[f>>0]=q;q=($(e[g+(p<<1)>>1]|0,o)|0)+n>>d;if((q|0)<0)q=0;else q=(q|0)>255?-1:q&255;a[f+1>>0]=q;q=($(e[h+(p<<1)>>1]|0,o)|0)+n>>d;if((q|0)<0)q=0;else q=(q|0)>255?-1:q&255;a[f+2>>0]=q;p=p+1|0;if((p|0)==(k|0))break;else f=f+l|0}i=m;return}function Rd(b,d,f,g,h,j,k){b=b|0;d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;o=i;l=c[b+12>>2]|0;m=c[b+16>>2]|0;n=c[b>>2]|0;b=c[b+36>>2]|0;if((j|0)>0)p=0;else{i=o;return}while(1){t=e[f+(p<<1)>>1]|0;s=(e[g+(p<<1)>>1]|0)-b|0;r=(e[h+(p<<1)>>1]|0)-b|0;q=t-s|0;u=($(q+r|0,l)|0)+m>>n;if((u|0)<0)u=0;else u=(u|0)>255?-1:u&255;a[d>>0]=u;s=($(s+t|0,l)|0)+m>>n;if((s|0)<0)s=0;else s=(s|0)>255?-1:s&255;a[d+1>>0]=s;q=($(q-r|0,l)|0)+m>>n;if((q|0)<0)q=0;else q=(q|0)>255?-1:q&255;a[d+2>>0]=q;p=p+1|0;if((p|0)==(j|0))break;else d=d+k|0}i=o;return}function Sd(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;d=i;if((b|0)==0|b>>>0>2147483583){k=0;i=d;return k|0}do if(!(c[1523]|0)){e=ta(64)|0;if((e|0)==(-1|0)){k=0;i=d;return k|0}else{c[1524]=ta(0)|0;c[1523]=6088;c[1522]=6088;c[1527]=6104;c[1526]=6104;k=e+16|0;a[e+15>>0]=-86;j=c[1527]|0;c[1527]=k;c[k>>2]=6104;c[e+20>>2]=j;c[j>>2]=k;j=e+24|0;k=c[1523]|0;c[1523]=j;c[j>>2]=6088;c[e+28>>2]=k;c[k>>2]=j;break}}while(0);e=b+40&-32;h=c[1524]|0;g=c[1522]|0;k=6092|0;while(1){f=c[k>>2]|0;b=f+ -8|0;k=c[f+ -4>>2]|0;if((k|0)==6104)j=h;else j=k;j=j-b|0;if(e>>>0>>0){h=12;break}if((f|0)==(g|0)){h=10;break}k=f+4|0;if((e|0)==(j|0)){h=15;break}}do if((h|0)==10)if((ta(e+32-j|0)|0)==(-1|0)){k=0;i=d;return k|0}else{c[1524]=ta(0)|0;k=c[g+ -4>>2]|0;f=g;h=12;break}else if((h|0)==15){j=c[f>>2]|0;k=c[k>>2]|0;c[j+4>>2]=k;c[k>>2]=j}while(0);if((h|0)==12){h=b+e|0;c[f+ -4>>2]=h;c[h>>2]=b;c[b+(e|4)>>2]=k;c[k>>2]=h;h=b+(e|8)|0;k=f+4|0;j=c[k>>2]|0;c[k>>2]=h;c[h>>2]=f;c[b+(e|12)>>2]=j;c[j>>2]=h;a[b+(e+ -1)>>0]=-86;j=c[f>>2]|0;k=c[k>>2]|0;c[j+4>>2]=k;c[k>>2]=j}a[b+ -1>>0]=85;k=f;i=d;return k|0}function Td(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;if(!b){i=d;return}g=b+ -8|0;e=c[1523]|0;c[1523]=b;c[b>>2]=6088;f=b+4|0;c[f>>2]=e;c[e>>2]=b;a[b+ -9>>0]=-86;e=c[g>>2]|0;if((e|0)!=6104?(a[e+ -1>>0]|0)==-86:0){g=c[b+ -4>>2]|0;c[e+4>>2]=g;c[g>>2]=e;b=c[b>>2]|0;g=c[f>>2]|0;c[b+4>>2]=g;c[g>>2]=b}else e=g;b=c[e+4>>2]|0;if((b|0)==6104){i=d;return}if((a[b+ -1>>0]|0)!=-86){i=d;return}g=c[b>>2]|0;h=c[b+4>>2]|0;c[g+4>>2]=h;c[h>>2]=g;h=e+8|0;g=c[h>>2]|0;j=e+12|0;f=c[j>>2]|0;c[g+4>>2]=f;c[f>>2]=g;f=b+8|0;g=b+12|0;e=c[g>>2]|0;c[g>>2]=h;c[h>>2]=f;c[j>>2]=e;c[e>>2]=h;f=c[f>>2]|0;g=c[g>>2]|0;c[f+4>>2]=g;c[g>>2]=f;i=d;return}function Ud(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;do if(a){if(!b){Td(a);e=0;break}e=Sd(b)|0;if(!e)e=0;else{f=(c[a+ -4>>2]|0)-a+ -1|0;ce(e|0,a|0,(f>>>0>b>>>0?b:f)|0)|0;Td(a)}}else e=Sd(b)|0;while(0);i=d;return e|0}function Vd(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;f=i;if(!d){h=0;i=f;return h|0}while(1){g=a[b>>0]|0;h=a[c>>0]|0;if(g<<24>>24!=h<<24>>24)break;d=d+ -1|0;if(!d){b=0;e=5;break}else{b=b+1|0;c=c+1|0}}if((e|0)==5){i=f;return b|0}h=(g&255)-(h&255)|0;i=f;return h|0}function Wd(){}function Xd(a){a=a|0;return(a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function Yd(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b>>c;return a>>>c|(b&(1<>c-32|0}function Zd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;b=b-d-(c>>>0>a>>>0|0)>>>0;return(D=b,a-c>>>0|0)|0}function _d(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return(D=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function $d(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function ae(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;i=b&3;h=d|d<<8|d<<16|d<<24;g=f&~3;if(i){i=b+4-i|0;while((b|0)<(i|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function be(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b<>>32-c;return a<=4096)return ua(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function de(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b>>>c;return a>>>c|(b&(1<>>c-32|0}function ee(b){b=b|0;var c=0;c=a[n+(b>>>24)>>0]|0;if((c|0)<8)return c|0;c=a[n+(b>>16&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[n+(b>>8&255)>>0]|0;if((c|0)<8)return c+16|0;return(a[n+(b&255)>>0]|0)+24|0}function fe(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return(a[m+(b>>>24)>>0]|0)+24|0}function ge(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;f=a&65535;d=b&65535;c=$(d,f)|0;e=a>>>16;d=(c>>>16)+($(d,e)|0)|0;b=b>>>16;a=$(b,f)|0;return(D=(d>>>16)+($(b,e)|0)+(((d&65535)+a|0)>>>16)|0,d+a<<16|c&65535|0)|0}function he(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;a=ge(e,f)|0;c=D;return(D=($(b,f)|0)+($(d,e)|0)+c|c&0,a|0|0)|0}function ie(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return za[a&1](b|0,c|0,d|0)|0}function je(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;Aa[a&1](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0)}function ke(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;Ba[a&7](b|0,c|0,d|0,e|0,f|0,g|0,h|0)}function le(a,b,c,d,e,f,g,h,i,j,k,l,m,n){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;Ca[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0,l|0,m|0,n|0)}function me(a,b){a=a|0;b=b|0;Da[a&1](b|0)}function ne(a,b,c){a=a|0;b=b|0;c=c|0;Ea[a&7](b|0,c|0)}function oe(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Fa[a&1](b|0,c|0,d|0,e|0,f|0,g|0)|0}function pe(a,b){a=a|0;b=b|0;return Ga[a&3](b|0)|0}function qe(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Ha[a&7](b|0,c|0,d|0)}function re(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Ia[a&1](b|0,c|0,d|0,e|0)|0}function se(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;Ja[a&3](b|0,c|0,d|0,e|0,f|0,g|0)}function te(a,b,c){a=a|0;b=b|0;c=c|0;return Ka[a&1](b|0,c|0)|0}function ue(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return La[a&1](b|0,c|0,d|0,e|0,f|0)|0}function ve(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;Ma[a&7](b|0,c|0,d|0,e|0)}function we(a,b,c){a=a|0;b=b|0;c=c|0;aa(0);return 0}function xe(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;aa(1)}function ye(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;aa(2)}function ze(a,b,c,d,e,f,g,h,i,j,k,l,m){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;aa(3)}function Ae(a){a=a|0;aa(4)}function Be(a,b){a=a|0;b=b|0;aa(5)}function Ce(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;aa(6);return 0}function De(a){a=a|0;aa(7);return 0}function Ee(a,b,c){a=a|0;b=b|0;c=c|0;aa(8)}function Fe(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;aa(9);return 0}function Ge(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;aa(10)}function He(a,b){a=a|0;b=b|0;aa(11);return 0}function Ie(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;aa(12);return 0}function Je(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;aa(13)} + + + + +// EMSCRIPTEN_END_FUNCS +var za=[we,Oc];var Aa=[xe,uc];var Ba=[ye,Pd,Qd,Rd,ec,xc,yc,Od];var Ca=[ze,vc,wc,ze];var Da=[Ae,Ob];var Ea=[Be,lc,qc,rc,sc,tc,Hc,sd];var Fa=[Ce,Mc];var Ga=[De,Lb,Nb,De];var Ha=[Ee,jc,kc,mc,nc,oc,pc,Ee];var Ia=[Fe,Mb];var Ja=[Ge,zc,Ac,Ge];var Ka=[He,Rb];var La=[Ie,Nc];var Ma=[Je,fc,gc,hc,ic,Je,Je,Je];return{_i64Subtract:Zd,_free:Td,_bpg_decoder_decode:Kd,_bpg_decoder_start:Id,_realloc:Ud,_i64Add:_d,_bpg_decoder_open:Jd,_bitshift64Ashr:Yd,_strlen:$d,_bpg_decoder_close:Md,_memset:ae,_malloc:Sd,_memcpy:ce,_bpg_decoder_get_line:Fd,_bpg_decoder_get_info:Ed,_llvm_bswap_i32:Xd,_bitshift64Shl:be,runPostSets:Wd,stackAlloc:Na,stackSave:Oa,stackRestore:Pa,setThrew:Qa,setTempRet0:Ta,getTempRet0:Ua,dynCall_iiii:ie,dynCall_viiiiiiiiii:je,dynCall_viiiiiii:ke,dynCall_viiiiiiiiiiiii:le,dynCall_vi:me,dynCall_vii:ne,dynCall_iiiiiii:oe,dynCall_ii:pe,dynCall_viii:qe,dynCall_iiiii:re,dynCall_viiiiii:se,dynCall_iii:te,dynCall_iiiiii:ue,dynCall_viiii:ve}}) + + +// EMSCRIPTEN_END_ASM +(l.v,l.w,T),Ra=l._i64Subtract=Z._i64Subtract;l._free=Z._free;l._bpg_decoder_decode=Z._bpg_decoder_decode;l._bpg_decoder_start=Z._bpg_decoder_start;l._realloc=Z._realloc;var Sa=l._i64Add=Z._i64Add;l._bpg_decoder_open=Z._bpg_decoder_open; +var Qa=l._bitshift64Ashr=Z._bitshift64Ashr,Ta=l._strlen=Z._strlen;l._bpg_decoder_close=Z._bpg_decoder_close;var Ua=l._memset=Z._memset,ua=l._malloc=Z._malloc,Ya=l._memcpy=Z._memcpy;l._bpg_decoder_get_line=Z._bpg_decoder_get_line;l._bpg_decoder_get_info=Z._bpg_decoder_get_info;var Pa=l._llvm_bswap_i32=Z._llvm_bswap_i32,Va=l._bitshift64Shl=Z._bitshift64Shl;l.runPostSets=Z.runPostSets;l.dynCall_iiii=Z.dynCall_iiii;l.dynCall_viiiiiiiiii=Z.dynCall_viiiiiiiiii;l.dynCall_viiiiiii=Z.dynCall_viiiiiii; +l.dynCall_viiiiiiiiiiiii=Z.dynCall_viiiiiiiiiiiii;l.dynCall_vi=Z.dynCall_vi;l.dynCall_vii=Z.dynCall_vii;l.dynCall_iiiiiii=Z.dynCall_iiiiiii;l.dynCall_ii=Z.dynCall_ii;l.dynCall_viii=Z.dynCall_viii;l.dynCall_iiiii=Z.dynCall_iiiii;l.dynCall_viiiiii=Z.dynCall_viiiiii;l.dynCall_iii=Z.dynCall_iii;l.dynCall_iiiiii=Z.dynCall_iiiiii;l.dynCall_viiii=Z.dynCall_viiii;z.d=Z.stackAlloc;z.m=Z.stackSave;z.q=Z.stackRestore;z.M=Z.setTempRet0;z.J=Z.getTempRet0; +if(X)if("function"===typeof l.locateFile?X=l.locateFile(X):l.memoryInitializerPrefixURL&&(X=l.memoryInitializerPrefixURL+X),u||w){var ab=l.readBinary(X);Q.set(ab,R)}else Ma(),Browser.V(X,function(a){Q.set(a,R);Na()},function(){b("could not load memory initializer "+X)});function ea(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}ea.prototype=Error();var $=k,W=function bb(){!l.calledRun&&cb&&db();l.calledRun||(W=bb)}; +function db(){function a(){if(!l.calledRun&&(l.calledRun=i,!F)){Ha||(Ha=i,U(Da));U(Ea);v&&$!==k&&l.a("pre-main prep time: "+(Date.now()-$)+" ms");if(l.postRun)for("function"==typeof l.postRun&&(l.postRun=[l.postRun]);l.postRun.length;)Ja(l.postRun.shift());U(Ga)}}$===k&&($=Date.now());if(!(0c.A(f,a,a.length))console.log("could not decode image");else{j=c.p(36);c.B(f,j);a=l.HEAPU32;g=a[j>>2];a=a[j+4>>2];c.n(j);c.F(f,1);p=c.p(4*g);j=c.H.createImageData(g,a);K=j.data;m=0;s=l.HEAPU8;g*=4;for(n=0;n 0) var gc = undefined")):v||aa?(l.read=function(a){var d=new XMLHttpRequest;d.open("GET",a,!1);d.send(k);return d.responseText},"undefined"!=typeof arguments&&(l.arguments=arguments),"undefined"!==typeof console?(l.print||(l.print=function(a){console.log(a)}),l.printErr||(l.printErr=function(a){console.log(a)})):l.print||(l.print=function(){}),v?window.Module=l:l.load=importScripts): +b("Unknown runtime environment. Where are we?");function da(a){eval.call(k,a)}!l.load&&l.read&&(l.load=function(a){da(l.read(a))});l.print||(l.print=function(){});l.printErr||(l.printErr=l.print);l.arguments||(l.arguments=[]);l.thisProgram||(l.thisProgram="./this.program");l.print=l.print;l.a=l.printErr;l.preRun=[];l.postRun=[];for(t in q)q.hasOwnProperty(t)&&(l[t]=q[t]); +var z={M:function(a){fa=a},J:function(){return fa},m:function(){return y},q:function(a){y=a},o:function(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?z.f:"i"===a[0]?(a=parseInt(a.substr(1)),x(0===a%8),a/8):0}},I:function(a){return Math.max(z.o(a),z.f)},O:16,Y:function(a,d,c){return!c&&("i64"==a||"double"==a)?8:!a?Math.min(d,8):Math.min(d||(a?z.I(a):0),z.f)},j:function(a, +d,c){return c&&c.length?(c.splice||(c=Array.prototype.slice.call(c)),c.splice(0,0,d),l["dynCall_"+a].apply(k,c)):l["dynCall_"+a].call(k,d)},c:[],t:function(a){for(var d=0;d=F&&A("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+F+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.");return d},g:function(a,d){return Math.ceil(a/(d?d:16))*(d?d:16)},da:function(a,d,c){return c?+(a>>>0)+4294967296*+(d>>>0):+(a>>>0)+4294967296*+(d|0)},r:8,f:4,P:0}; +l.Runtime=z;z.addFunction=z.t;z.removeFunction=z.L;var G=!1,H,ga,fa;function x(a,d){a||A("Assertion failed: "+d)}function ha(a){var d=l["_"+a];if(!d)try{d=eval("_"+a)}catch(c){}x(d,"Cannot call unknown function "+a+" (perhaps LLVM optimizations or closure removed it?)");return d}var ia,ja; +(function(){function a(a){a=a.toString().match(f).slice(1);return{arguments:a[0],body:a[1],returnValue:a[2]}}var d=0,c={stackSave:function(){d=z.m()},stackRestore:function(){z.q(d)},arrayToC:function(a){var c=z.d(a.length);ka(a,c);return c},stringToC:function(a){var c=0;a!==k&&(a!==h&&0!==a)&&(c=z.d((a.length<<2)+1),la(a,c));return c}},e={string:c.stringToC,array:c.arrayToC};ja=function(a,f,g,i){var a=ha(a),s=[];if(i)for(var n=0;n>0]=d;break;case "i8":I[a>>0]=d;break;case "i16":J[a>>1]=d;break;case "i32":K[a>>2]=d;break;case "i64":ga=[d>>>0,(H=d,1<=+na(H)?0>>0:~~+qa((H-+(~~H>>>0))/4294967296)>>>0:0)];K[a>>2]=ga[0];K[a+4>>2]=ga[1];break;case "float":M[a>>2]=d;break;case "double":N[a>>3]=d;break;default:A("invalid type for setValue: "+c)}}l.setValue=ma; +l.getValue=function(a,d){d=d||"i8";"*"===d.charAt(d.length-1)&&(d="i32");switch(d){case "i1":return I[a>>0];case "i8":return I[a>>0];case "i16":return J[a>>1];case "i32":return K[a>>2];case "i64":return K[a>>2];case "float":return M[a>>2];case "double":return N[a>>3];default:A("invalid type for setValue: "+d)}return k};var ra=2,ta=4;l.ALLOC_NORMAL=0;l.ALLOC_STACK=1;l.ALLOC_STATIC=ra;l.ALLOC_DYNAMIC=3;l.ALLOC_NONE=ta; +function O(a,d,c,e){var f,g;"number"===typeof a?(f=j,g=a):(f=!1,g=a.length);var i="string"===typeof d?d:k,c=c==ta?e:[ua,z.d,z.N,z.b][c===h?ra:c](Math.max(g,i?1:d.length));if(f){e=c;x(0==(c&3));for(a=c+(g&-4);e>2]=0;for(a=c+g;e>0]=0;return c}if("i8"===i)return a.subarray||a.slice?P.set(a,c):P.set(new Uint8Array(a),c),c;for(var e=0,m,p;eR?2*R:R+16777216;R!==F&&(l.a("increasing TOTAL_MEMORY to "+R+" to be compliant with the asm.js spec"),F=R); +x("undefined"!==typeof Int32Array&&"undefined"!==typeof Float64Array&&!!(new Int32Array(1)).subarray&&!!(new Int32Array(1)).set,"JS engine does not provide full typed array support");var S=new ArrayBuffer(F);I=new Int8Array(S);J=new Int16Array(S);K=new Int32Array(S);P=new Uint8Array(S);wa=new Uint16Array(S);xa=new Uint32Array(S);M=new Float32Array(S);N=new Float64Array(S);K[0]=255;x(255===P[0]&&0===P[3],"Typed arrays 2 must be run on a little-endian system");l.HEAP=h;l.buffer=S;l.HEAP8=I; +l.HEAP16=J;l.HEAP32=K;l.HEAPU8=P;l.HEAPU16=wa;l.HEAPU32=xa;l.HEAPF32=M;l.HEAPF64=N;function T(a){for(;0>0]=a[c],c+=1}l.writeStringToMemory=la;function ka(a,d){for(var c=0;c>0]=a[c]}l.writeArrayToMemory=ka; +l.writeAsciiToMemory=function(a,d,c){for(var e=0;e>0]=a.charCodeAt(e);c||(I[d+a.length>>0]=0)};if(!Math.imul||-5!==Math.imul(4294967295,5))Math.imul=function(a,d){var c=a&65535,e=d&65535;return c*e+((a>>>16)*e+c*(d>>>16)<<16)|0};Math.ca=Math.imul;var na=Math.abs,qa=Math.ceil,pa=Math.floor,oa=Math.min,V=0,La=k,W=k;function Ma(){V++;l.monitorRunDependencies&&l.monitorRunDependencies(V)}l.addRunDependency=Ma; +function Na(){V--;l.monitorRunDependencies&&l.monitorRunDependencies(V);if(0==V&&(La!==k&&(clearInterval(La),La=k),W)){var a=W;W=k;a()}}l.removeRunDependency=Na;l.preloadedImages={};l.preloadedAudios={};var X=k,Q=8,B=Q+6112;Da.push(); +O([0,0,1,0,1,2,0,1,2,3,1,2,3,2,3,3,0,1,0,2,1,0,3,2,1,0,3,2,1,3,2,3,0,0,1,0,1,2,0,1,2,3,0,1,2,3,4,0,1,2,3,4,5,0,1,2,3,4,5,6,0,1,2,3,4,5,6,7,1,2,3,4,5,6,7,2,3,4,5,6,7,3,4,5,6,7,4,5,6,7,5,6,7,6,7,7,0,1,0,2,1,0,3,2,1,0,4,3,2,1,0,5,4,3,2,1,0,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,7,6,5,4,3,2,7,6,5,4,3,7,6,5,4,7,6,5,7,6,7,40,45,51,57,64,72,0,0,29,0,0,0,30,0,0,0,31,0,0,0,32,0,0,0,33,0,0,0,33,0,0,0,34,0,0,0,34,0,0,0,35,0,0,0,35,0,0,0,36,0,0,0,36,0,0,0,37,0,0,0,37,0,0,0,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2, +3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,11,11,11,12,12,0,0,0,0,0,0,0,2,5,9,1,4,8,12,3,7,11,14,6,10,13,15,0,0,0,0,0,0,0,0,0,2,1,3,0,0,0,0,0,2,5,9,14,20,27,35,1,4,8,13,19,26,34,42,3,7,12,18,25,33,41,48,6,11,17,24,32,40,47,53,10,16,23,31,39,46,52,57,15,22,30,38,45,51, +56,60,21,29,37,44,50,55,59,62,28,36,43,49,54,58,61,63,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,0,1,2,3,16,17,18,19,4,5,6,7,20,21,22,23,8,9,10,11,24,25,26,27,12,13,14,15,28,29,30,31,32,33,34,35,48,49,50,51,36,37,38,39,52,53,54,55,40,41,42,43,56,57,58,59,44,45,46,47,60,61,62,63,0,1,4,5,2,3,4,5,6,6,8,8,7,7,8,8,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,2,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,2,1,0,0,2,1,0,0,2,1,0,0,2,1,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,153,200,139, +141,157,154,154,154,154,154,154,154,154,184,154,154,154,184,63,139,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,153,138,138,111,141,94,138,182,154,139,139,139,139,139,139,110,110,124,125,140,153,125,127,140,109,111,143,127,111,79,108,123,63,110,110,124,125,140,153,125,127,140,109,111,143,127,111,79,108,123,63,91,171,134,141,111,111,125,110,110,94,124,108,124,107,125,141,179,153,125,107,125,141,179,153,125,107,125,141,179,153,125,140,139,182,182,152,136,152,136,153,136,139,111, +136,139,111,141,111,140,92,137,138,140,152,138,139,153,74,149,92,139,107,122,152,140,179,166,182,140,227,122,197,138,153,136,167,152,152,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,185,107,139,126,154,197,185,201,154,154,154,149,154,139,154,154,154,152,139,110,122,95,79,63,31,31,153,153,153,153,140,198,140,198,168,79,124,138,94,153,111,149,107,167,154,139,139,139,139,139,139,125,110,94,110,95,79,125,111,110,78,110,111,111,95,94,108,123,108,125,110, +94,110,95,79,125,111,110,78,110,111,111,95,94,108,123,108,121,140,61,154,155,154,139,153,139,123,123,63,153,166,183,140,136,153,154,166,183,140,136,153,154,166,183,140,136,153,154,170,153,123,123,107,121,107,121,167,151,183,140,151,183,140,140,140,154,196,196,167,154,152,167,182,182,134,149,136,153,121,136,137,169,194,166,167,154,167,137,182,107,167,91,122,107,167,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,160,107,139,126,154,197,185,201,154,154, +154,134,154,139,154,154,183,152,139,154,137,95,79,63,31,31,153,153,153,153,169,198,169,198,168,79,224,167,122,153,111,149,92,167,154,139,139,139,139,139,139,125,110,124,110,95,94,125,111,111,79,125,126,111,111,79,108,123,93,125,110,124,110,95,94,125,111,111,79,125,126,111,111,79,108,123,93,121,140,61,154,170,154,139,153,139,123,123,63,124,166,183,140,136,153,154,166,183,140,136,153,154,166,183,140,136,153,154,170,153,138,138,122,121,122,121,167,151,183,140,151,183,140,140,140,154,196,167,167,154, +152,167,182,182,134,149,136,153,121,136,122,169,208,166,167,154,152,167,182,107,167,91,107,107,167,154,154,154,154,154,154,154,154,154,154,154,154,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,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,10,11,13,14,16,18,20,22,24,0,0,29,30,31,32,33,33,34,34,35,35,36,36,37,37, +0,0,104,101,118,99,0,0,0,0,128,5,0,0,0,0,0,0,0,0,0,0,53,54,50,72,34,48,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,172,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,10,1,0,0,0,0,0,1,2,2,2,2,3,5,7,8,10,12,13,15,17,18,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,31,0,0,0,0,0,7,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,32,26,21,17,13,9,5,2,0,254,251,247,243,239,235,230,224,230,235,239,243,247,251,254,0, +2,5,9,13,17,21,26,32,0,0,0,0,0,0,0,0,240,154,249,114,252,138,253,30,254,122,254,197,254,0,255,197,254,122,254,30,254,138,253,114,252,154,249,0,240,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,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,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,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,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,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,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,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,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,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,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,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,64,90,90,90,89,88,87,85,83,82,80,78,75,73,70,67,64,61,57,54,50,46,43,38,36,31,25,22,18,13,9,4,1,2,0,3,4,0,0,0,255,0,1,0,0,255,0,1,255,255,1,1,1,255,255,1,16,16,16,16,17,18,21,24,16,16,16,16,17,19,22,25,16,16,17,18,20,22,25,29,16,16,18,21,24,27,31,36,17,17,20,24,30,35,41,47,18,19,22,27,35,44,54,65,21,22,25,31, +41,54,70,88,24,25,29,36,47,65,88,115,16,16,16,16,17,18,20,24,16,16,16,17,18,20,24,25,16,16,17,18,20,24,25,28,16,17,18,20,24,25,28,33,17,18,20,24,25,28,33,41,18,20,24,25,28,33,41,54,20,24,25,28,33,41,54,71,24,25,28,33,41,54,71,91,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0,255,255,255,127,0,0,0,0,0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7, +7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,3,1,1,0,36,56,37,56,38,56,0,0,0,0,0,0,56,0,0,0,0,0,0,0,3,1,0,16,36,56,37,56,38,56,0,0,0,0,0,0,5,0,0,0,0,0,0,0,3,0,0,16,36,56,37,56,38,56,0,0,0,0,0,0,8,0,0,0,0,0,0,0,1,0,0,0,36,56,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,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,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,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,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,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,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,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,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,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,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,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,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,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],"i8",ta,z.r);var Oa=z.g(O(12,"i8",ra),8);x(0==Oa%8);l._llvm_bswap_i32=Pa;l._bitshift64Ashr=Qa;l._i64Subtract=Ra;function Y(a){Y.G||(C=C+4095&-4096,Y.G=j,x(z.b),Y.u=z.b,z.b=function(){A("cannot dynamically allocate, sbrk now has control")});var d=C;0!=a&&Y.u(a);return d}l._i64Add=Sa;l._strlen=Ta;l._memset=Ua;l._bitshift64Shl=Va;function Wa(a){l.exit(a)} +function Xa(a){return 0.5!==Math.abs(a%1)?Math.round(a):a+a%2+(0>a?1:-1)}l._memcpy=Ya;ya=y=z.g(B);za=ya+Ba;Aa=C=z.g(za);x(Aa>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function Sa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function Ta(a){a=a|0;D=a}function Ua(){return D|0}function Va(b,d){b=b|0;d=d|0;var e=0,f=0;e=i;if(!(a[(c[b+204>>2]|0)+43>>0]|0)){i=e;return}f=c[(c[b+200>>2]|0)+13128>>2]|0;d=(d|0)%(f|0)|0;if((d|0)!=2?!((f|0)==2&(d|0)==0):0){i=e;return}ce(c[b+152>>2]|0,c[b+136>>2]|0,199)|0;i=e;return}function Wa(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;g=b+204|0;f=c[g>>2]|0;if((c[(c[f+1668>>2]|0)+(c[b+2500>>2]<<2)>>2]|0)==(d|0)){Xa(b);f=b+1449|0;if(a[f>>0]|0){j=c[g>>2]|0;if((a[j+42>>0]|0)!=0?(j=c[j+1676>>2]|0,(c[j+(d<<2)>>2]|0)!=(c[j+(d+ -1<<2)>>2]|0)):0)h=5}else h=5;if((h|0)==5)Ya(b);if(a[b+1448>>0]|0){i=e;return}if(!(a[(c[g>>2]|0)+43>>0]|0)){i=e;return}g=c[(c[b+200>>2]|0)+13128>>2]|0;if((d|0)%(g|0)|0){i=e;return}if((g|0)==1){Ya(b);i=e;return}if((a[f>>0]|0)!=1){i=e;return}ce(c[b+136>>2]|0,c[b+152>>2]|0,199)|0;i=e;return}if((a[f+42>>0]|0)!=0?(j=c[f+1676>>2]|0,(c[j+(d<<2)>>2]|0)!=(c[j+(d+ -1<<2)>>2]|0)):0){if((a[b+141>>0]|0)==1)Za(c[b+136>>2]|0);else Xa(b);Ya(b);f=c[g>>2]|0}if(!(a[f+43>>0]|0)){i=e;return}f=b+200|0;if((d|0)%(c[(c[f>>2]|0)+13128>>2]|0)|0){i=e;return}d=b+136|0;_a((c[d>>2]|0)+224|0)|0;if((a[b+141>>0]|0)==1)Za(c[d>>2]|0);else Xa(b);if((c[(c[f>>2]|0)+13128>>2]|0)==1){Ya(b);i=e;return}else{ce(c[d>>2]|0,c[b+152>>2]|0,199)|0;i=e;return}}function Xa(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;e=a+136|0;a=c[e>>2]|0;d=a+204|0;cd(d,1);g=a+212|0;f=c[g>>2]|0;h=0-f&7;if(h){cd(d,h);f=c[g>>2]|0}_c((c[e>>2]|0)+224|0,(c[d>>2]|0)+((f|0)/8|0)|0,(7-f+(c[a+216>>2]|0)|0)/8|0);i=b;return}function Ya(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;g=i;f=c[b+1440>>2]|0;e=2-f|0;e=(a[b+2060>>0]|0)==0|(f|0)==2?e:e^3;f=b+2112|0;b=b+136|0;h=0;do{j=d[680+(e*199|0)+h>>0]|0;l=a[f>>0]|0;k=l<<24>>24;if(l<<24>>24<0)k=0;else k=(k|0)>51?51:k;j=((j<<3&120)+ -16+(($(k,((j>>>4)*5|0)+ -45|0)|0)>>4)<<1)+ -127|0;j=j>>31^j;if((j|0)>124)j=j&1|124;a[(c[b>>2]|0)+h>>0]=j;h=h+1|0}while((h|0)!=199);a[(c[b>>2]|0)+199>>0]=0;a[(c[b>>2]|0)+200>>0]=0;a[(c[b>>2]|0)+201>>0]=0;a[(c[b>>2]|0)+202>>0]=0;i=g;return}function Za(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;d=a+224|0;e=c[a+240>>2]|0;f=c[d>>2]|0;e=(f&1|0)==0?e:e+ -1|0;e=(f&511|0)==0?e:e+ -1|0;a=(c[a+244>>2]|0)-e|0;if((a|0)<0){i=b;return}_c(d,e,a);i=b;return}function _a(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;f=a+4|0;d=c[f>>2]|0;e=d+ -2|0;c[f>>2]=e;g=c[a>>2]|0;if((g|0)>=(e<<17|0)){g=(c[a+16>>2]|0)-(c[a+12>>2]|0)|0;i=b;return g|0}d=(d+ -258|0)>>>31;c[f>>2]=e<>2]=g;if(g&65535){g=0;i=b;return g|0}Ab(a);g=0;i=b;return g|0}function $a(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a)|0;i=b;return a|0}function ab(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;h=d[e>>0]|0;j=b+4|0;k=c[j>>2]|0;l=d[2880+((k<<1&384)+(h|512))>>0]|0;k=k-l|0;m=k<<17;n=c[b>>2]|0;g=m-n>>31;c[b>>2]=n-(g&m);c[j>>2]=(g&l-k)+k;h=g^h;a[e>>0]=a[h+4032>>0]|0;e=h&1;h=c[j>>2]|0;g=d[2880+h>>0]|0;c[j>>2]=h<>2]<>2]=g;if(g&65535){i=f;return e|0}j=b+16|0;h=c[j>>2]|0;c[b>>2]=(((d[h+1>>0]|0)<<1|(d[h>>0]|0)<<9)+ -65535<<7-(d[2880+((g+ -1^g)>>15)>>0]|0))+g;if(h>>>0>=(c[b+20>>2]|0)>>>0){i=f;return e|0}c[j>>2]=h+2;i=f;return e|0}function bb(a){a=a|0;var b=0,d=0;b=i;a=a+136|0;d=c[a>>2]|0;if(!(ab(d+224|0,d+1|0)|0)){d=0;i=b;return d|0}d=(cb((c[a>>2]|0)+224|0)|0)==0;d=d?1:2;i=b;return d|0}function cb(a){a=a|0;var b=0,d=0,e=0;b=i;d=c[a>>2]<<1;c[a>>2]=d;if(!(d&65534)){Ab(a);d=c[a>>2]|0}e=c[a+4>>2]<<17;if((d|0)<(e|0)){e=0;i=b;return e|0}c[a>>2]=d-e;e=1;i=b;return e|0}function db(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function eb(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;d=c[(c[a+200>>2]|0)+52>>2]|0;d=(d|0)>10?31:(1<0)a=0;else{f=0;i=b;return f|0}while(1){f=a+1|0;if(!(cb((c[e>>2]|0)+224|0)|0)){d=4;break}if((f|0)<(d|0))a=f;else{a=f;d=4;break}}if((d|0)==4){i=b;return a|0}return 0}function fb(a){a=a|0;var b=0;b=i;a=cb((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function gb(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function hb(a){a=a|0;var b=0;b=i;a=_a((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function ib(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+5|0)|0;i=b;return a|0}function jb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;a=a+136|0;g=9;e=0;while(1){h=c[a>>2]|0;f=e;e=e+1|0;if(!(ab(h+224|0,h+g|0)|0)){e=f;g=0;break}if((e|0)>=5){f=0;g=0;d=4;break}else g=10}do if((d|0)==4){while(1){d=0;if(!(cb((c[a>>2]|0)+224|0)|0)){d=5;break}g=(1<>2]|0)+224|0)|0)<>2]|0)+224|0)|0;i=b;return a|0}function lb(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+176|0)|0;i=b;return a|0}function mb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;e=a[(c[b+204>>2]|0)+1633>>0]|0;e=(e&255)<5?5:e&255;f=b+136|0;if(!e){g=0;i=d;return g|0}else b=0;while(1){h=c[f>>2]|0;g=b+1|0;if(!(ab(h+224|0,h+177|0)|0)){e=4;break}if((g|0)<(e|0))b=g;else{b=g;e=4;break}}if((e|0)==4){i=d;return b|0}return 0}function nb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0;j=i;k=c[b+200>>2]|0;n=(1<>2])+ -1|0;l=n&g;m=c[k+13064>>2]|0;h=f>>m;m=g>>m;g=c[b+136>>2]|0;if((a[g+308>>0]|0)==0?(n&f|0)==0:0)f=0;else{f=h+ -1+($(c[k+13140>>2]|0,m)|0)|0;f=d[(c[b+4336>>2]|0)+f>>0]|0}if((a[g+309>>0]|0)==0&(l|0)==0){n=0;m=(f|0)>(e|0);m=m&1;n=(n|0)>(e|0);n=n&1;f=g+224|0;m=m|2;n=m+n|0;n=g+n|0;n=ab(f,n)|0;i=j;return n|0}n=($(c[k+13140>>2]|0,m+ -1|0)|0)+h|0;n=d[(c[b+4336>>2]|0)+n>>0]|0;m=(f|0)>(e|0);m=m&1;n=(n|0)>(e|0);n=n&1;f=g+224|0;m=m|2;n=m+n|0;n=g+n|0;n=ab(f,n)|0;i=j;return n|0}function ob(a,b){a=a|0;b=b|0;var d=0;d=i;b=c[a+136>>2]|0;b=(ab(b+224|0,b+13|0)|0)==0;i=d;return(b?3:0)|0}function pb(a){a=a|0;var b=0;b=i;a=_a((c[a+136>>2]|0)+224|0)|0;i=b;return a|0}function qb(a){a=a|0;var b=0;b=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+17|0)|0;i=b;return a|0}function rb(a){a=a|0;var b=0,d=0,e=0;b=i;e=a+136|0;d=0;while(1){a=d+1|0;if(!(cb((c[e>>2]|0)+224|0)|0)){a=d;d=4;break}if((a|0)<2)d=a;else{d=4;break}}if((d|0)==4){i=b;return a|0}return 0}function sb(a){a=a|0;var b=0,d=0;b=i;d=a+136|0;a=(cb((c[d>>2]|0)+224|0)|0)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=(cb((c[d>>2]|0)+224|0)|0|a)<<1;a=cb((c[d>>2]|0)+224|0)|0|a;i=b;return a|0}function tb(a){a=a|0;var b=0,d=0;b=i;a=a+136|0;d=c[a>>2]|0;if(!(ab(d+224|0,d+18|0)|0)){d=4;i=b;return d|0}d=(cb((c[a>>2]|0)+224|0)|0)<<1;d=cb((c[a>>2]|0)+224|0)|0|d;i=b;return d|0}function ub(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(42-b)|0)|0;i=d;return a|0}function vb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(b+42)|0)|0;i=d;return a|0}function wb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+((b|0)==0|40)|0)|0;i=d;return a|0}function xb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;a=a+136|0;f=(b<<2)+166|0;e=0;while(1){g=c[a>>2]|0;b=e+1|0;if(!(ab(g+224|0,g+(f+e)|0)|0)){b=e;a=4;break}if((b|0)<4)e=b;else{a=4;break}}if((a|0)==4){i=d;return b|0}return 0}function yb(a,b){a=a|0;b=b|0;var d=0;d=i;a=c[a+136>>2]|0;a=ab(a+224|0,a+(b+174)|0)|0;i=d;return a|0}function zb(f,g,h,j,k,l){f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Da=0,Ea=0,Fa=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0;n=i;i=i+96|0;v=n+24|0;s=n+8|0;t=n;u=f+136|0;o=c[u>>2]|0;p=c[f+160>>2]|0;m=c[p+(l<<2)+32>>2]|0;r=f+200|0;T=c[r>>2]|0;h=$(h>>c[T+(l<<2)+13180>>2],m)|0;h=(c[p+(l<<2)>>2]|0)+(h+(g>>c[T+(l<<2)+13168>>2]<>2]))|0;T=(l|0)!=0;g=o+320|0;p=T?o+11680|0:g;x=v+0|0;q=x+64|0;do{a[x>>0]=0;x=x+1|0}while((x|0)<(q|0));S=1<>2]|0;q=S<>0]|0)){A=a[o+272>>0]|0;C=f+204|0;Ma=c[C>>2]|0;if((a[Ma+21>>0]|0)!=0?(d[Ma+1629>>0]|0)>=(j|0):0){F=c[u>>2]|0;F=ab(F+224|0,F+(T&1|46)|0)|0}else F=0;if(y){B=c[r>>2]|0;G=B;B=(c[B+13192>>2]|0)+A|0}else{B=c[C>>2]|0;if((l|0)==1)B=(c[f+2072>>2]|0)+(c[B+28>>2]|0)+(a[o+302>>0]|0)|0;else B=(c[f+2076>>2]|0)+(c[B+32>>2]|0)+(a[o+303>>0]|0)|0;B=B+A|0;G=c[r>>2]|0;A=c[G+13192>>2]|0;E=0-A|0;if((B|0)>=(E|0))E=(B|0)>57?57:B;do if((c[G+4>>2]|0)==1){if((E|0)>=30)if((E|0)>43){E=E+ -6|0;break}else{E=c[176+(E+ -30<<2)>>2]|0;break}}else E=(E|0)>51?51:E;while(0);B=A+E|0}A=(c[G+52>>2]|0)+j|0;E=A+ -5|0;A=1<>0]|0)>>0]<>0];if((a[G+634>>0]|0)!=0?!((F|0)!=0&(j|0)>2):0){H=c[C>>2]|0;G=(a[H+68>>0]|0)==0?G+635|0:H+69|0;H=((c[o+31244>>2]|0)!=1?3:0)+l|0;C=G+((j+ -2|0)*384|0)+(H<<6)|0;if((j|0)>3)ia=a[G+((j+ -4|0)*6|0)+H+1536>>0]|0;else ia=16}else{ia=16;C=0}}else{A=0;ia=0;B=0;C=0;E=0;F=0}I=(j<<1)+ -1|0;if(y){G=(j*3|0)+ -6+(j+ -1>>2)|0;J=j+1>>2}else{G=15;J=j+ -2|0}if((I|0)>0){L=G+52|0;H=0;while(1){Ma=c[u>>2]|0;K=H+1|0;if(!(ab(Ma+224|0,Ma+(L+(H>>J))|0)|0))break;if((K|0)<(I|0))H=K;else{H=K;break}}K=G+70|0;G=0;while(1){Ma=c[u>>2]|0;L=G+1|0;if(!(ab(Ma+224|0,Ma+(K+(G>>J))|0)|0))break;if((L|0)<(I|0))G=L;else{G=L;break}}if((H|0)>3){I=(H>>1)+ -1|0;K=cb((c[u>>2]|0)+224|0)|0;if((I|0)>1){J=1;do{K=cb((c[u>>2]|0)+224|0)|0|K<<1;J=J+1|0}while((J|0)!=(I|0))}H=K+((H&1|2)<3){J=(G>>1)+ -1|0;K=cb((c[u>>2]|0)+224|0)|0;if((J|0)>1){I=1;do{K=cb((c[u>>2]|0)+224|0)|0|K<<1;I=I+1|0}while((I|0)!=(J|0))}I=H;L=K+((G&1|2)<>2;N=L>>2;if((k|0)==1){G=I;H=L;P=d[536+(L<<3)+I>>0]|0;J=488;K=504;L=496;I=520;break}else if(k){J=I;K=L;w=49;break}P=d[(I&3)+(392+((L&3)<<2))>>0]|0;if((S|0)==8){G=I;H=L;P=(d[416+(N<<1)+M>>0]<<4)+P|0;J=496;K=8;L=488;I=24;break}else if((S|0)==16){G=I;H=L;P=(d[392+(N<<2)+M>>0]<<4)+P|0;J=8;K=8;L=24;I=24;break}else if((S|0)==4){G=I;H=L;J=408;K=8;L=408;I=24;break}else{G=I;H=L;P=(d[424+(N<<3)+M>>0]<<4)+P|0;J=40;K=8;L=104;I=24;break}}else{J=L;K=I;M=L>>2;N=I>>2;w=49}while(0);if((w|0)==49){G=J;H=K;P=d[536+(J<<3)+K>>0]|0;J=496;K=520;L=488;I=504}O=P+1|0;P=P>>4;if((P|0)>-1){Q=(1<0;l=R?90:88;S=S+ -1>>2;W=T?27:0;U=(j|0)==2;T=W+3|0;V=(j|0)==3;Z=(k|0)==0?9:15;_=y?0:27;da=(F|0)==0;aa=y?42:43;fa=y?40:41;ba=y?2:0;ea=o+31244|0;ca=x&-17;ga=f+204|0;Y=((B|0)<0)<<31>>31;X=((A|0)<0)<<31>>31;ha=(F|0)!=0&(j|0)>2;k=(j|0)<4;ia=ia&255;ma=(y&1)<<1;ja=ma|1;ra=1;ka=P;oa=0;xa=16;while(1){na=ka<<4;wa=a[J+ka>>0]|0;ta=wa&255;va=a[L+ka>>0]|0;ua=va&255;la=(ka|0)>0;if((ka|0)<(P|0)&la){if((ta|0)<(Q|0))pa=d[v+(ta+1<<3)+ua>>0]|0;else pa=0;if((ua|0)<(Q|0))pa=(d[ua+1+(v+(ta<<3))>>0]|0)+pa|0;ya=c[u>>2]|0;ya=(ab(ya+224|0,ya+(((pa|0)>1?1:pa)+l)|0)|0)&255;a[v+(ta<<3)+ua>>0]=ya;qa=1}else{if(!((ta|0)==(M|0)&(ua|0)==(N|0)))if(!(wa<<24>>24))ya=va<<24>>24==0&1;else ya=0;else ya=1;a[v+(ta<<3)+ua>>0]=ya;qa=0}na=O-na|0;pa=(ka|0)==(P|0);if(pa){a[s>>0]=na+255;sa=na+ -2|0;na=1}else{sa=15;na=0}if((ta|0)<(S|0))za=(a[v+(ta+1<<3)+ua>>0]|0)!=0&1;else za=0;if((ua|0)<(S|0))za=((a[ua+1+(v+(ta<<3))>>0]|0)!=0&1)<<1|za;do if(ya<<24>>24!=0&(sa|0)>-1){if(!(c[(c[r>>2]|0)+13100>>2]|0))if(U){wa=600;va=W}else w=73;else if(da){ya=(a[z>>0]|0)!=0;if(ya|U){wa=ya?664:600;va=ya?fa:W}else w=73}else{wa=664;va=fa}do if((w|0)==73){w=0;ya=(za<<4)+616|0;if(!y){wa=ya;va=W+(V?9:12)|0;break}va=(va|wa)<<24>>24==0?W:T;if(V){wa=ya;va=va+Z|0;break}else{wa=ya;va=va+21|0;break}}while(0);if((sa|0)>0){ya=va+92|0;do{Ma=c[u>>2]|0;if(ab(Ma+224|0,Ma+(ya+(d[wa+((d[I+sa>>0]<<2)+(d[K+sa>>0]|0))>>0]|0))|0)|0){a[s+(na&255)>>0]=sa;qa=0;na=na+1<<24>>24}sa=sa+ -1|0}while((sa|0)>0)}if(qa){a[s+(na&255)>>0]=0;qa=na+1<<24>>24;break}if(c[(c[r>>2]|0)+13100>>2]|0)if(da?(a[z>>0]|0)==0:0)w=87;else qa=aa;else w=87;if((w|0)==87){w=0;qa=(ka|0)==0?_:va+2|0}Ma=c[u>>2]|0;if((ab(Ma+224|0,Ma+(qa+92)|0)|0)==1){a[s+(na&255)>>0]=0;qa=na+1<<24>>24}else qa=na}else qa=na;while(0);na=qa&255;a:do if(qa<<24>>24){qa=la?ba:0;if(!(c[(c[r>>2]|0)+13116>>2]|0))Fa=0;else{if(da?(a[z>>0]|0)==0:0)oa=ma;else oa=ja;Fa=(d[o+oa+199>>0]|0)>>>2}sa=qa|(ra|0)==0&(pa^1)&1;Da=a[s>>0]|0;va=Da&255;qa=na>>>0>8?8:na;if(!qa){pa=-1;ra=1}else{ya=sa<<2;pa=-1;ra=1;wa=0;do{Ma=ra+ya|0;La=c[u>>2]|0;Ma=(ab(La+224|0,La+((R?Ma+16|0:Ma)+136)|0)|0)&255;a[t+wa>>0]=Ma;if(!(Ma<<24>>24))ra=((ra+ -1|0)>>>0<2&1)+ra|0;else{pa=(pa|0)==-1?wa:pa;ra=0}wa=wa+1|0}while((wa|0)<(qa|0))}wa=na+ -1|0;qa=a[s+wa>>0]|0;ya=qa&255;do if(!(a[z>>0]|0)){if((c[ea>>2]|0)==1?!((c[(c[r>>2]|0)+13104>>2]|0)==0|da|(ca|0)!=10):0){va=0;break}va=(va-ya|0)>3&1}else va=0;while(0);if((pa|0)!=-1){La=c[u>>2]|0;La=ab(La+224|0,La+((R?sa|4:sa)|160)|0)|0;Ma=t+pa|0;a[Ma>>0]=(d[Ma>>0]|0)+La}sa=(va|0)==0;if((a[(c[ga>>2]|0)+4>>0]|0)==0|sa){wa=0;va=0;do{va=cb((c[u>>2]|0)+224|0)|0|va<<1;wa=wa+1|0}while((wa|0)<(na|0));za=va<<16-na}else{va=wa&255;if(!((wa&255)<<24>>24))ya=0;else{wa=0;ya=0;do{ya=cb((c[u>>2]|0)+224|0)|0|ya<<1;wa=wa+1|0}while((wa|0)<(va|0))}za=ya<<17-na}ta=ta<<2;va=ua<<2;ua=o+oa+199|0;wa=0;Ha=0;Aa=xa;Ea=0;while(1){xa=Da&255;ya=(d[K+xa>>0]|0)+ta|0;xa=(d[I+xa>>0]|0)+va|0;b:do if((wa|0)<8){Ia=(d[t+wa>>0]|0)+1|0;Ma=(wa|0)==(pa|0);if((Ia|0)==((Ma?3:2)|0)&0==((Ma?0:0)|0))Ja=0;else{Ja=0;break}while(1){Ka=Ja+1|0;if(!(cb((c[u>>2]|0)+224|0)|0)){w=120;break}if((Ka|0)<31)Ja=Ka;else{w=124;break}}do if((w|0)==120){w=0;if((Ja|0)>=3){Ka=Ja;w=124;break}if((Fa|0)>0){Ka=0;La=0;do{La=cb((c[u>>2]|0)+224|0)|0|La<<1;Ka=Ka+1|0}while((Ka|0)!=(Fa|0))}else La=0;Ka=La+(Ja<0){La=Fa+ -3+Ka|0;Ka=0;Ma=0;do{Ma=cb((c[u>>2]|0)+224|0)|0|Ma<<1;Ka=Ka+1|0}while((Ka|0)!=(La|0))}else Ma=0;Ka=Ma+((1<>31|0,Ia|0,0)|0;Ja=D;La=3<>31;Ma=c[(c[r>>2]|0)+13116>>2]|0;do if((Ja|0)>(Na|0)|(Ja|0)==(Na|0)&Ia>>>0>La>>>0){La=Fa+1|0;if(Ma){Fa=La;break}Fa=(Fa|0)>3?4:La;break b}while(0);if(!((Ma|0)!=0&(Ha|0)==0))break;Ha=a[ua>>0]|0;La=(Ha&255)>>>2;if((Ka|0)>=(3<>0]=Ha+1<<24>>24;Ha=1;break}if((Ka<<1|0)>=(1<>24==0){Ha=1;break}a[ua>>0]=Ha+ -1<<24>>24;Ha=1}else{Ia=0;while(1){Ja=Ia+1|0;if(!(cb((c[u>>2]|0)+224|0)|0)){w=138;break}if((Ja|0)<31)Ia=Ja;else{w=142;break}}do if((w|0)==138){w=0;if((Ia|0)>=3){Ja=Ia;w=142;break}if((Fa|0)>0){Ja=0;Ka=0;do{Ka=cb((c[u>>2]|0)+224|0)|0|Ka<<1;Ja=Ja+1|0}while((Ja|0)!=(Fa|0))}else Ka=0;Ka=Ka+(Ia<0){Ka=Fa+ -3+Ja|0;Ja=0;La=0;do{La=cb((c[u>>2]|0)+224|0)|0|La<<1;Ja=Ja+1|0}while((Ja|0)!=(Ka|0))}else La=0;Ka=La+((1<>31;Ma=c[(c[r>>2]|0)+13116>>2]|0;do if((Ka|0)>=(3<3?4:La;break b}while(0);if(!((Ma|0)!=0&(Ha|0)==0))break;La=a[ua>>0]|0;Ha=(La&255)>>>2;if((Ka|0)>=(3<>0]=La+1<<24>>24;Ha=1;break}if((Ka<<1|0)>=(1<>24==0){Ha=1;break}a[ua>>0]=La+ -1<<24>>24;Ha=1}while(0);do if(!((a[(c[ga>>2]|0)+4>>0]|0)==0|sa)){Ea=_d(Ia|0,Ja|0,Ea|0,0)|0;if(Da<<24>>24!=qa<<24>>24)break;Na=(Ea&1|0)==0;Ma=Zd(0,0,Ia|0,Ja|0)|0;Ia=Na?Ia:Ma;Ja=Na?Ja:D}while(0);Na=(za&32768|0)==0;Da=Zd(0,0,Ia|0,Ja|0)|0;Da=Na?Ia:Da;Ia=Na?Ja:D;za=za<<1&131070;Ja=Da&65535;do if(!(a[z>>0]|0)){do if(!((a[(c[r>>2]|0)+634>>0]|0)==0|ha)){if(!((xa|ya|0)!=0|k)){Aa=ia;break}if((j|0)==3)Aa=(xa<<3)+ya|0;else if((j|0)==4)Aa=(xa>>>1<<3)+(ya>>>1)|0;else if((j|0)==5)Aa=(xa>>>2<<3)+(ya>>>2)|0;else Aa=(xa<<2)+ya|0;Aa=d[C+Aa>>0]|0}while(0);Da=he(Da|0,Ia|0,B|0,Y|0)|0;Da=he(Da|0,D|0,Aa|0,((Aa|0)<0)<<31>>31|0)|0;Da=_d(Da|0,D|0,A|0,X|0)|0;Da=Yd(Da|0,D|0,E|0)|0;Ia=D;if((Ia|0)<0){Ja=(Da&-32768|0)==-32768&(Ia&268435455|0)==268435455?Da&65535:-32768;break}else{Ja=Ia>>>0>0|(Ia|0)==0&Da>>>0>32767?32767:Da&65535;break}}while(0);b[p+((xa<>1]=Ja;wa=wa+1|0;if((wa|0)>=(na|0)){xa=Aa;break a}Da=a[s+wa>>0]|0}}while(0);if(la)ka=ka+ -1|0;else break}}do if(a[z>>0]|0){if((c[(c[r>>2]|0)+13104>>2]|0)!=0?(x&-17|0)==10:0)Ga[c[f+2632>>2]&7](p,j&65535,(x|0)==26&1)}else{if(F){if(((j|0)==2?(c[(c[r>>2]|0)+13096>>2]|0)!=0:0)?(c[o+31244>>2]|0)==1:0){s=0;do{La=p+(15-s<<1)|0;Ma=b[La>>1]|0;Na=p+(s<<1)|0;b[La>>1]=b[Na>>1]|0;b[Na>>1]=Ma;s=s+1|0}while((s|0)!=8)}s=j&65535;Ca[c[f+2628>>2]&7](p,s);if(!(c[(c[r>>2]|0)+13104>>2]|0))break;if((c[o+31244>>2]|0)!=1)break;if((x&-17|0)!=10)break;Ga[c[f+2632>>2]&7](p,s,(x|0)==26&1);break}if(y&(c[o+31244>>2]|0)==1&(j|0)==2){Ba[c[f+2636>>2]&7](p);break}r=(G|0)>(H|0)?G:H;if(!r){Ba[c[f+(j+ -2<<2)+2656>>2]&7](p);break}s=H+4+G|0;do if((r|0)>=4){if((r|0)<8){s=(s|0)<8?s:8;break}if((r|0)<12)s=(s|0)<24?s:24}else s=(s|0)<4?s:4;while(0);Ca[c[f+(j+ -2<<2)+2640>>2]&7](p,s)}while(0);if(!(a[o+304>>0]|0)){Na=j+ -2|0;Na=f+(Na<<2)+2612|0;Na=c[Na>>2]|0;Ga[Na&7](h,p,m);i=n;return}if((q|0)<=0){Na=j+ -2|0;Na=f+(Na<<2)+2612|0;Na=c[Na>>2]|0;Ga[Na&7](h,p,m);i=n;return}o=c[o+284>>2]|0;r=0;do{Na=p+(r<<1)|0;b[Na>>1]=(($(b[g+(r<<1)>>1]|0,o)|0)>>>3)+(e[Na>>1]|0);r=r+1|0}while((r|0)!=(q|0));Na=j+ -2|0;Na=f+(Na<<2)+2612|0;Na=c[Na>>2]|0;Ga[Na&7](h,p,m);i=n;return}function Ab(a){a=a|0;var b=0,e=0,f=0;b=i;f=a+16|0;e=c[f>>2]|0;c[a>>2]=(c[a>>2]|0)+ -65535+((d[e+1>>0]|0)<<1|(d[e>>0]|0)<<9);if(e>>>0>=(c[a+20>>2]|0)>>>0){i=b;return}c[f>>2]=e+2;i=b;return}function Bb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;f=i;h=b+136|0;n=c[h>>2]|0;g=b+200|0;j=c[g>>2]|0;m=c[j+13080>>2]|0;q=(1<>2]|0)+24>>2]|0);o=m&d;p=m&e;k=c[j+13140>>2]|0;j=c[j+13064>>2]|0;l=o>>j;j=p>>j;if(!(q&d))o=0;else o=(o&q|0)!=0;if(!(q&e))p=0;else p=(p&q|0)!=0;q=n+203|0;if((a[q>>0]|0)==0?(m&(e|d)|0)!=0:0)d=c[n+276>>2]|0;else{a[q>>0]=(a[n+300>>0]|0)==0&1;d=a[b+2112>>0]|0}if(o){e=l+ -1+($(j,k)|0)|0;e=a[(c[b+4316>>2]|0)+e>>0]|0}else e=d;if(p){d=($(j+ -1|0,k)|0)+l|0;d=a[(c[b+4316>>2]|0)+d>>0]|0}b=e+1+d>>1;h=c[h>>2]|0;j=c[h+280>>2]|0;if(!j){a[h+272>>0]=b;i=f;return}g=c[(c[g>>2]|0)+13192>>2]|0;b=j+52+b+(g<<1)|0;if((b|0)>0)j=b;else j=-52-g+1+b|0;a[h+272>>0]=b-g-j+((j|0)%(g+52|0)|0);i=f;return}function Cb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;g=i;j=c[b+136>>2]|0;k=b+200|0;do if((e|0)>0&(e&7|0)==0){if(((a[b+2062>>0]|0)==0?(c[j+31312>>2]&4|0)!=0:0)?((e|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0)break;if(((a[(c[b+204>>2]|0)+53>>0]|0)==0?(c[j+31312>>2]&8|0)!=0:0)?((e|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0)break;h=1<0){l=b+2596|0;m=b+4320|0;n=0;do{o=n+d+($(c[l>>2]|0,e)|0)>>2;a[(c[m>>2]|0)+o>>0]=2;n=n+4|0}while((n|0)<(h|0))}}while(0);if(!((d|0)>0&(d&7|0)==0)){i=g;return}if(((a[b+2062>>0]|0)==0?(c[j+31312>>2]&1|0)!=0:0)?((d|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0){i=g;return}if(((a[(c[b+204>>2]|0)+53>>0]|0)==0?(c[j+31312>>2]&2|0)!=0:0)?((d|0)%(1<>2]|0)+13080>>2]|0)|0|0)==0:0){i=g;return}h=1<>2]|0,k+e|0)|0)+d>>2;a[(c[b>>2]|0)+o>>0]=2;k=k+4|0}while((k|0)<(h|0));i=g;return}function Db(e,f,g,h){e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0;j=i;i=i+32|0;o=j+8|0;w=j;n=j+18|0;r=j+16|0;l=e+200|0;J=c[l>>2]|0;u=c[J+13120>>2]|0;k=(u-h|0)<=(f|0);b[n>>1]=0;b[r>>1]=0;v=c[J+13080>>2]|0;t=1<>v,c[J+13128>>2]|0)|0)+(f>>v)|0;s=c[e+2508>>2]|0;m=c[s+(v<<3)+4>>2]|0;x=c[s+(v<<3)>>2]|0;if((c[J+68>>2]|0)!=0?(a[J+13056>>0]|0)!=0:0)p=1;else p=(a[(c[e+204>>2]|0)+40>>0]|0)!=0;q=(f|0)!=0;if(q){v=v+ -1|0;y=c[s+(v<<3)>>2]|0;v=c[s+(v<<3)+4>>2]|0}else{y=0;v=0}s=t+f|0;s=(s|0)>(u|0)?u:s;t=t+g|0;z=c[J+13124>>2]|0;t=(t|0)>(z|0)?z:t;z=(s|0)==(u|0)?s:s+ -8|0;u=(t|0)>(g|0);if(u){J=q?f:8;M=(J|0)<(s|0);P=q?f+ -8|0:0;E=e+2596|0;O=e+4320|0;H=e+4316|0;B=w+4|0;C=e+160|0;D=n+1|0;Q=r+1|0;K=e+4300|0;L=e+4284|0;I=e+4324|0;F=e+4304|0;G=e+4288|0;A=(P|0)>=(z|0);T=x;S=m;N=g;do{if(M){R=N+4|0;W=S+ -2&-2;U=J;do{Z=c[E>>2]|0;ba=($(Z,N)|0)+U>>2;_=c[I>>2]|0;ba=a[_+ba>>0]|0;ca=ba&255;Z=a[_+(($(Z,R)|0)+U>>2)>>0]|0;_=Z&255;ba=ba<<24>>24!=0;Z=Z<<24>>24==0;do if(!(Z&(ba^1))){V=U+ -1|0;X=c[l>>2]|0;aa=c[X+13064>>2]|0;Y=$(N>>aa,c[X+13140>>2]|0)|0;da=c[H>>2]|0;aa=(a[da+(Y+(V>>aa))>>0]|0)+1+(a[da+(Y+(U>>aa))>>0]|0)>>1;Y=aa+T|0;if((Y|0)<0)Y=0;else Y=(Y|0)>51?51:Y;Y=d[1280+Y>>0]|0;if(ba){ba=(ca<<1)+W+aa|0;if((ba|0)<0)ba=0;else ba=(ba|0)>53?53:ba;ba=d[1336+ba>>0]|0}else ba=0;c[w>>2]=ba;if(Z)Z=0;else{Z=(_<<1)+W+aa|0;if((Z|0)<0)Z=0;else Z=(Z|0)>53?53:Z;Z=d[1336+Z>>0]|0}c[B>>2]=Z;ca=c[C>>2]|0;Z=c[ca+32>>2]|0;da=$(Z,N)|0;X=(c[ca>>2]|0)+((U<>2])+da)|0;if(p){a[n>>0]=Ib(e,V,N)|0;a[D>>0]=Ib(e,V,R)|0;a[r>>0]=Ib(e,U,N)|0;a[Q>>0]=Ib(e,U,R)|0;Ja[c[F>>2]&3](X,Z,Y,w,n,r);break}else{Ja[c[G>>2]&3](X,Z,Y,w,n,r);break}}while(0);U=U+8|0}while((U|0)<(s|0))}if(!((N|0)==0|A)){R=N+ -1|0;V=S;S=P;do{Y=$(c[E>>2]|0,N)|0;Z=c[O>>2]|0;aa=a[Z+(Y+S>>2)>>0]|0;ba=aa&255;U=S+4|0;Y=a[Z+(Y+U>>2)>>0]|0;Z=Y&255;aa=aa<<24>>24!=0;Y=Y<<24>>24==0;do if(!(Y&(aa^1))){W=c[l>>2]|0;V=c[W+13064>>2]|0;_=S>>V;T=c[W+13140>>2]|0;da=($(R>>V,T)|0)+_|0;X=c[H>>2]|0;_=(a[X+da>>0]|0)+1+(a[X+(($(N>>V,T)|0)+_)>>0]|0)>>1;T=(S|0)>=(f|0);V=T?m:v;T=T?x:y;X=_+T|0;if((X|0)<0)X=0;else X=(X|0)>51?51:X;X=d[1280+X>>0]|0;if(aa){aa=(ba<<1)+(V+ -2&-2)+_|0;if((aa|0)<0)aa=0;else aa=(aa|0)>53?53:aa;aa=d[1336+aa>>0]|0}else aa=0;c[w>>2]=aa;if(Y)Y=0;else{Y=(Z<<1)+(V+ -2&-2)+_|0;if((Y|0)<0)Y=0;else Y=(Y|0)>53?53:Y;Y=d[1336+Y>>0]|0}c[B>>2]=Y;ca=c[C>>2]|0;Y=c[ca+32>>2]|0;da=$(Y,N)|0;W=(c[ca>>2]|0)+((S<>2])+da)|0;if(p){a[n>>0]=Ib(e,S,R)|0;a[D>>0]=Ib(e,U,R)|0;a[r>>0]=Ib(e,S,N)|0;a[Q>>0]=Ib(e,U,N)|0;Ja[c[K>>2]&3](W,Y,X,w,n,r);break}else{Ja[c[L>>2]&3](W,Y,X,w,n,r);break}}while(0);S=S+8|0}while((S|0)<(z|0));S=V}N=N+8|0}while((N|0)<(t|0));J=c[l>>2]|0}else S=m;if(c[J+4>>2]|0){C=q?v:m;F=e+2596|0;D=e+4320|0;v=e+4316|0;x=o+4|0;w=e+160|0;B=n+1|0;A=r+1|0;G=e+4308|0;E=e+4292|0;H=e+4324|0;z=e+4312|0;y=e+4296|0;I=1;do{O=1<>2];P=1<>2];if(u){N=O<<3;L=q?f:N;K=(L|0)<(s|0);J=P<<3;M=q?f-N|0:0;O=O<<2;P=P<<2;Q=g;do{if(K){R=Q+P|0;T=L;do{W=c[F>>2]|0;Y=($(W,Q)|0)+T>>2;da=c[H>>2]|0;Y=(a[da+Y>>0]|0)==2;W=(a[da+(($(W,R)|0)+T>>2)>>0]|0)==2;do if(Y|W){U=T+ -1|0;V=c[l>>2]|0;da=c[V+13064>>2]|0;_=U>>da;X=c[V+13140>>2]|0;Z=$(Q>>da,X)|0;aa=c[v>>2]|0;ba=T>>da;X=$(R>>da,X)|0;X=(a[aa+(X+_)>>0]|0)+1+(a[aa+(X+ba)>>0]|0)>>1;if(Y)Y=Jb(e,(a[aa+(Z+ba)>>0]|0)+1+(a[aa+(Z+_)>>0]|0)>>1,I,S)|0;else Y=0;c[o>>2]=Y;if(W)W=Jb(e,X,I,S)|0;else W=0;c[x>>2]=W;ca=c[w>>2]|0;W=c[ca+(I<<2)+32>>2]|0;da=$(W,Q>>c[V+(I<<2)+13180>>2])|0;V=(c[ca+(I<<2)>>2]|0)+((T>>c[V+(I<<2)+13168>>2]<>2])+da)|0;if(p){a[n>>0]=Ib(e,U,Q)|0;a[B>>0]=Ib(e,U,R)|0;a[r>>0]=Ib(e,T,Q)|0;a[A>>0]=Ib(e,T,R)|0;Aa[c[z>>2]&3](V,W,o,n,r);break}else{Aa[c[y>>2]&3](V,W,o,n,r);break}}while(0);T=T+N|0}while((T|0)<(s|0))}if(Q){U=s-((s|0)==(c[(c[l>>2]|0)+13120>>2]|0)?0:N)|0;if((M|0)<(U|0)){T=Q+ -1|0;S=M;do{W=$(c[F>>2]|0,Q)|0;da=c[D>>2]|0;R=S+O|0;X=(a[da+(W+S>>2)>>0]|0)==2;W=(a[da+(W+R>>2)>>0]|0)==2;do if(X|W){if(X){da=c[l>>2]|0;ca=c[da+13064>>2]|0;Y=S>>ca;da=c[da+13140>>2]|0;aa=($(T>>ca,da)|0)+Y|0;ba=c[v>>2]|0;Y=(a[ba+aa>>0]|0)+1+(a[ba+(($(Q>>ca,da)|0)+Y)>>0]|0)>>1}else Y=0;if(W){da=c[l>>2]|0;ca=c[da+13064>>2]|0;V=R>>ca;da=c[da+13140>>2]|0;aa=($(T>>ca,da)|0)+V|0;ba=c[v>>2]|0;V=(a[ba+aa>>0]|0)+1+(a[ba+(($(Q>>ca,da)|0)+V)>>0]|0)>>1}else V=0;if(X)X=Jb(e,Y,I,C)|0;else X=0;c[o>>2]=X;if(W)V=Jb(e,V,I,m)|0;else V=0;c[x>>2]=V;da=c[l>>2]|0;ca=c[w>>2]|0;V=c[ca+(I<<2)+32>>2]|0;W=$(V,Q>>c[da+13184>>2])|0;W=(c[ca+(I<<2)>>2]|0)+((S>>c[da+13172>>2]<>2])+W)|0;if(p){a[n>>0]=Ib(e,S,T)|0;a[B>>0]=Ib(e,R,T)|0;a[r>>0]=Ib(e,S,Q)|0;a[A>>0]=Ib(e,R,Q)|0;Aa[c[G>>2]&3](W,V,o,n,r);break}else{Aa[c[E>>2]&3](W,V,o,n,r);break}}while(0);S=S+N|0}while((S|0)<(U|0));S=C}else S=C}Q=Q+J|0}while((Q|0)<(t|0))}I=I+1|0;J=c[l>>2]|0}while((I|0)!=3)}if(!(a[J+12941>>0]|0)){if((a[e+140>>0]&1)==0|k^1){i=j;return}i=j;return}n=(c[J+13124>>2]|0)-h|0;l=(g|0)==0;m=(f|0)==0;if(!(l|m))Eb(e,f-h|0,g-h|0);n=(n|0)>(g|0);if(!(m|n))Eb(e,f-h|0,g);k=k^1;!(l|k)?(Eb(e,f,g-h|0),(a[e+140>>0]&1)!=0):0;if(n|k){i=j;return}Eb(e,f,g);if(!(a[e+140>>0]&1)){i=j;return}i=j;return}function Eb(e,f,g){e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0;v=i;i=i+48|0;j=v+24|0;h=v+42|0;u=v+40|0;r=v+16|0;n=v+8|0;m=v;k=e+200|0;S=c[k>>2]|0;s=c[S+13080>>2]|0;q=f>>s;s=g>>s;D=S+13128|0;p=($(s,c[D>>2]|0)|0)+q|0;L=c[e+204>>2]|0;N=L+1668|0;M=c[(c[N>>2]|0)+(p<<2)>>2]|0;l=e+2504|0;o=c[l>>2]|0;t=o+(p*148|0)|0;b[h>>1]=0;b[u>>1]=0;c[r>>2]=0;E=($(c[D>>2]|0,s)|0)+q|0;E=a[(c[e+4352>>2]|0)+E>>0]|0;if((a[L+42>>0]|0)!=0?(a[L+53>>0]|0)==0:0){R=1;O=1}else{R=E<<24>>24==0&1;O=0}G=(q|0)==0;c[j>>2]=G&1;I=(s|0)==0;A=j+4|0;c[A>>2]=I&1;H=(q|0)==((c[D>>2]|0)+ -1|0);z=j+8|0;c[z>>2]=H&1;F=(s|0)==((c[S+13132>>2]|0)+ -1|0);w=j+12|0;c[w>>2]=F&1;if(R<<24>>24){if(G)J=0;else{if(O){J=c[L+1676>>2]|0;J=(c[J+(M<<2)>>2]|0)!=(c[J+(c[(c[N>>2]|0)+(p+ -1<<2)>>2]<<2)>>2]|0)&1}else J=0;if(E<<24>>24==0?(pa=$(c[D>>2]|0,s)|0,oa=c[e+4328>>2]|0,(c[oa+(pa+q<<2)>>2]|0)!=(c[oa+(q+ -1+pa<<2)>>2]|0)):0)K=1;else K=J;a[h>>0]=K}if(H)K=0;else{if(O){K=c[L+1676>>2]|0;K=(c[K+(M<<2)>>2]|0)!=(c[K+(c[(c[N>>2]|0)+(p+1<<2)>>2]<<2)>>2]|0)&1}else K=0;if(E<<24>>24==0?(pa=$(c[D>>2]|0,s)|0,oa=c[e+4328>>2]|0,(c[oa+(pa+q<<2)>>2]|0)!=(c[oa+(q+1+pa<<2)>>2]|0)):0)P=1;else P=K;a[h+1>>0]=P}if(I)P=0;else{if(O){P=c[L+1676>>2]|0;P=(c[P+(M<<2)>>2]|0)!=(c[P+(c[(c[N>>2]|0)+(p-(c[D>>2]|0)<<2)>>2]<<2)>>2]|0)&1}else P=0;if(E<<24>>24==0?(pa=c[D>>2]|0,na=($(pa,s)|0)+q|0,oa=c[e+4328>>2]|0,(c[oa+(na<<2)>>2]|0)!=(c[oa+(($(pa,s+ -1|0)|0)+q<<2)>>2]|0)):0)Q=1;else Q=P;a[u>>0]=Q}if(F)L=0;else{if(O){L=c[L+1676>>2]|0;L=(c[L+(M<<2)>>2]|0)!=(c[L+(c[(c[N>>2]|0)+((c[D>>2]|0)+p<<2)>>2]<<2)>>2]|0)&1}else L=0;if(E<<24>>24==0?(pa=c[D>>2]|0,na=($(pa,s)|0)+q|0,oa=c[e+4328>>2]|0,(c[oa+(na<<2)>>2]|0)!=(c[oa+(($(pa,s+1|0)|0)+q<<2)>>2]|0)):0)M=1;else M=L;a[u+1>>0]=M}if(!G)if(I)B=47;else{if(!(E<<24>>24)){pa=c[D>>2]|0;na=($(pa,s)|0)+q|0;oa=c[e+4328>>2]|0;if(J<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(q+ -1+($(pa,s+ -1|0)|0)<<2)>>2]|0):0)B=38;else M=1}else if(!(J<<24>>24))B=38;else M=1;if((B|0)==38)M=P<<24>>24!=0&1;a[r>>0]=M;B=40}else B=40;if((B|0)==40)if(!I){if(!H){if(!(E<<24>>24)){pa=c[D>>2]|0;na=($(pa,s)|0)+q|0;oa=c[e+4328>>2]|0;if(K<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(q+1+($(pa,s+ -1|0)|0)<<2)>>2]|0):0)B=45;else I=1}else if(!(K<<24>>24))B=45;else I=1;if((B|0)==45)I=P<<24>>24!=0&1;a[r+1>>0]=I;B=47}}else B=47;if((B|0)==47?!(H|F):0){if(!(E<<24>>24)){pa=c[D>>2]|0;na=($(pa,s)|0)+q|0;oa=c[e+4328>>2]|0;if(K<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(q+1+($(pa,s+1|0)|0)<<2)>>2]|0):0)B=51;else H=1}else if(!(K<<24>>24))B=51;else H=1;if((B|0)==51)H=L<<24>>24!=0&1;a[r+2>>0]=H}if(!(G|F)){if(!(E<<24>>24)){pa=c[D>>2]|0;na=($(pa,s)|0)+q|0;oa=c[e+4328>>2]|0;if(J<<24>>24==0?(c[oa+(na<<2)>>2]|0)==(c[oa+(q+ -1+($(pa,s+1|0)|0)<<2)>>2]|0):0)B=57;else D=1}else if(!(J<<24>>24))B=57;else D=1;if((B|0)==57)D=L<<24>>24!=0&1;a[r+3>>0]=D}}O=(c[S+4>>2]|0)!=0?3:1;I=e+160|0;H=e+168|0;P=e+2672|0;J=s<<1;G=J+ -1|0;D=n+4|0;E=s+ -1|0;Q=q+1|0;L=q+ -1|0;J=J+2|0;F=m+4|0;K=s+1|0;N=q<<1;M=N+ -1|0;N=N+2|0;R=e+((R&255)<<2)+2676|0;na=S;Y=0;while(1){ka=c[na+(Y<<2)+13168>>2]|0;_=f>>ka;ha=c[na+(Y<<2)+13180>>2]|0;Z=g>>ha;ba=c[I>>2]|0;S=c[ba+(Y<<2)+32>>2]|0;U=1<>2];X=U>>ka;W=U>>ha;ka=c[na+13120>>2]>>ka;ca=ka-_|0;X=(X|0)>(ca|0)?ca:X;ha=c[na+13124>>2]>>ha;ca=ha-Z|0;W=(W|0)>(ca|0)?ca:W;ca=$(S,Z)|0;ga=c[na+56>>2]|0;ca=(_<>2]|0;aa=ba+ca|0;U=U+2<>2]|0;fa=1<>0]|0;if((ia|0)==1){ea=X<0){da=V;ba=0;ca=aa;while(1){ce(da|0,ca|0,ea|0)|0;ba=ba+1|0;if((ba|0)==(W|0))break;else{da=da+U|0;ca=ca+S|0}}}Gb(e,aa,S,_,Z,X,W,Y,q,s);Ha[c[P>>2]&1](aa,V,S,U,t,j,X,W,Y);Hb(e,aa,V,S,U,f,g,X,W,Y);a[T>>0]=3}else if((ia|0)==2){ja=c[j>>2]|0;ia=c[z>>2]|0;la=c[w>>2]|0;do if(!(c[A>>2]|0)){pa=1-ja|0;oa=pa<>2]=ba+(ca-S-oa);c[D>>2]=(c[e+(Y<<2)+172>>2]|0)+(($(ka,G)|0)+_-pa<>2]|0,E)|0)|0;pa=c[n+(((a[(c[l>>2]|0)+(pa*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0;if(!ga){a[oa>>0]=a[pa>>0]|0;na=c[k>>2]|0;oa=fa;break}else{b[oa>>1]=b[pa>>1]|0;oa=fa;break}}else oa=0;while(0);pa=($(c[na+13128>>2]|0,E)|0)+q|0;na=X<>2]|0)+(pa*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0)+oa|0,na|0)|0;if((ia|0)!=1){na=oa+na|0;pa=Q+($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)|0;ma=da+(na+ma)|0;na=(c[n+(((a[(c[l>>2]|0)+(pa*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0)+na|0;if(!ga){a[ma>>0]=a[na>>0]|0;break}else{b[ma>>1]=b[na>>1]|0;break}}}while(0);do if(!la){pa=1-ja|0;oa=pa<>2]=ba+(($(W,S)|0)+ca-oa);c[F>>2]=(c[e+(Y<<2)+172>>2]|0)+(($(ka,J)|0)+_-pa<>2]|0)+13128>>2]|0,K)|0)|0;ma=c[m+(((a[(c[l>>2]|0)+(ma*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0;if(!ga){a[ka>>0]=a[ma>>0]|0;ka=fa;break}else{b[ka>>1]=b[ma>>1]|0;ka=fa;break}}else ka=0;while(0);pa=($(c[(c[k>>2]|0)+13128>>2]|0,K)|0)+q|0;ma=X<>2]|0)+(pa*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0)+ka|0,ma|0)|0;if((ia|0)!=1){ka=ka+ma|0;pa=Q+($(c[(c[k>>2]|0)+13128>>2]|0,K)|0)|0;la=da+(ka+la)|0;ka=(c[m+(((a[(c[l>>2]|0)+(pa*148|0)+Y+142>>0]|0)==3&1)<<2)>>2]|0)+ka|0;if(!ga){a[la>>0]=a[ka>>0]|0;break}else{b[la>>1]=b[ka>>1]|0;break}}}while(0);do if(!ja){pa=L+($(c[(c[k>>2]|0)+13128>>2]|0,s)|0)|0;if((a[(c[l>>2]|0)+(pa*148|0)+Y+142>>0]|0)==3){la=da+U|0;ja=(c[e+(Y<<2)+184>>2]|0)+(($(ha,M)|0)+Z<0;if(!ga){if(ka)ka=0;else{ja=0;break}while(1){a[la>>0]=a[ja>>0]|0;ka=ka+1|0;if((ka|0)==(W|0)){ja=0;break}else{la=la+U|0;ja=ja+fa|0}}}else{if(ka)ka=0;else{ja=0;break}while(1){b[la>>1]=b[ja>>1]|0;ka=ka+1|0;if((ka|0)==(W|0)){ja=0;break}else{la=la+U|0;ja=ja+fa|0}}}}else ja=1}else ja=0;while(0);do if(!ia){pa=Q+($(c[(c[k>>2]|0)+13128>>2]|0,s)|0)|0;if((a[(c[l>>2]|0)+(pa*148|0)+Y+142>>0]|0)==3){ia=da+((X<>2]|0)+(($(ha,N)|0)+Z<0;if(!ga){if(ka)B=0;else break;while(1){a[ia>>0]=a[ha>>0]|0;B=B+1|0;if((B|0)==(W|0)){C=0;B=96;break}else{ia=ia+U|0;ha=ha+fa|0}}}else{if(ka)B=0;else break;while(1){b[ia>>1]=b[ha>>1]|0;B=B+1|0;if((B|0)==(W|0)){C=0;B=96;break}else{ia=ia+U|0;ha=ha+fa|0}}}}else{C=1;B=96}}else{C=0;B=96}while(0);if((B|0)==96?(B=0,x=ja<0):0){ea=da+(ea-x)|0;da=0;ba=ba+(ca-x)|0;while(1){ce(ea|0,ba|0,y|0)|0;da=da+1|0;if((da|0)==(W|0))break;else{ea=ea+U|0;ba=ba+S|0}}}Gb(e,aa,S,_,Z,X,W,Y,q,s);Ea[c[R>>2]&3](aa,V,S,U,t,j,X,W,Y,h,u,r);Hb(e,aa,V,S,U,f,g,X,W,Y);a[T>>0]=3}Y=Y+1|0;if((Y|0)>=(O|0))break;na=c[k>>2]|0}i=v;return}function Fb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;h=c[a+200>>2]|0;k=((c[h+13120>>2]|0)-e|0)>(b|0);h=((c[h+13124>>2]|0)-e|0)>(d|0);j=(d|0)==0;g=(b|0)==0;if(!(j|g))Db(a,b-e|0,d-e|0,e);if(!(j|k))Db(a,b,d-e|0,e);if(g|h){i=f;return}Db(a,b-e|0,d,e);i=f;return}function Gb(d,e,f,g,h,j,k,l,m,n){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0;o=i;q=c[d+200>>2]|0;p=c[q+56>>2]|0;s=c[q+13120>>2]>>c[q+(l<<2)+13168>>2];q=c[q+13124>>2]>>c[q+(l<<2)+13180>>2];u=d+(l<<2)+172|0;t=n<<1;r=j<>2]|0)+(($(s,t)|0)+g<>2]|0)+(($(s,t|1)|0)+g<>2]|0;l=m<<1;t=r+(($(q,l)|0)+h<0;if(n){if(g){r=t;t=0;s=e;while(1){a[r>>0]=a[s>>0]|0;t=t+1|0;if((t|0)==(k|0))break;else{r=r+m|0;s=s+f|0}}r=c[d>>2]|0}}else if(g){d=0;s=e;while(1){b[t>>1]=b[s>>1]|0;d=d+1|0;if((d|0)==(k|0))break;else{t=t+m|0;s=s+f|0}}}h=r+(($(q,l|1)|0)+h<>0]=a[j>>0]|0;p=p+1|0;if((p|0)==(k|0))break;else{h=h+m|0;j=j+f|0}}i=o;return}else{if(g)p=0;else{i=o;return}while(1){b[h>>1]=b[j>>1]|0;p=p+1|0;if((p|0)==(k|0))break;else{h=h+m|0;j=j+f|0}}i=o;return}}function Hb(b,d,e,f,g,h,j,k,l,m){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;n=i;t=c[b+200>>2]|0;if(!(a[(c[b+204>>2]|0)+40>>0]|0)){if(!(a[t+13056>>0]|0)){i=n;return}if(!(c[t+68>>2]|0)){i=n;return}}p=b+200|0;C=c[t+13084>>2]|0;v=1<>2]|0;s=c[t+(m<<2)+13180>>2]|0;m=h>>C;z=j>>C;k=k+h>>C;l=l+j>>C;t=v>>o<>2];if((z|0)>=(l|0)){i=n;return}u=(m|0)<(k|0);b=b+4348|0;v=v>>s;w=(v|0)>0;do{if(u){x=z-j|0;y=m;do{A=c[p>>2]|0;C=($(c[A+13156>>2]|0,z)|0)+y|0;if((a[(c[b>>2]|0)+C>>0]|0)!=0?(r=c[A+13084>>2]|0,q=x<>s,r=y-h<>o<>2],w):0){C=e+(($(q,g)|0)+r)|0;A=0;B=d+(($(q,f)|0)+r)|0;while(1){ce(B|0,C|0,t|0)|0;A=A+1|0;if((A|0)==(v|0))break;else{C=C+g|0;B=B+f|0}}}y=y+1|0}while((y|0)!=(k|0))}z=z+1|0}while((z|0)!=(l|0));i=n;return}function Ib(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0;f=i;g=c[a+200>>2]|0;h=c[g+13084>>2]|0;if((e|b|0)<0){e=2;i=f;return e|0}b=b>>h;e=e>>h;h=c[g+13156>>2]|0;if((b|0)>=(h|0)){e=2;i=f;return e|0}if((e|0)>=(c[g+13160>>2]|0)){e=2;i=f;return e|0}e=($(h,e)|0)+b|0;e=d[(c[a+4348>>2]|0)+e>>0]|0;i=f;return e|0}function Jb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0;h=i;j=c[b+204>>2]|0;e=(c[((f|0)==1?j+28|0:j+32|0)>>2]|0)+e|0;if((e|0)<0)e=0;else e=(e|0)>57?57:e;do if((c[(c[b+200>>2]|0)+4>>2]|0)==1){if((e|0)>=30)if((e|0)>43){e=e+ -6|0;break}else{e=d[1392+(e+ -30)>>0]|0;break}}else if((e|0)<0)e=0;else e=(e|0)>51?51:e;while(0);g=g+2+e|0;if((g|0)<0){j=0;j=1336+j|0;j=a[j>>0]|0;j=j&255;i=h;return j|0}j=(g|0)>53?53:g;j=1336+j|0;j=a[j>>0]|0;j=j&255;i=h;return j|0}function Kb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;k=b+4376|0;c[k>>2]=0;a:do if((e|0)>1){m=0;while(1){if(!(a[d+m>>0]|0)){if((m|0)>0){l=m+ -1|0;l=(a[d+l>>0]|0)==0?l:m}else l=m;m=l+2|0;if(((m|0)<(e|0)?(a[d+(l+1)>>0]|0)==0:0)?(j=a[d+m>>0]|0,(j&255)<4):0)break}else l=m;m=l+2|0;if((l+3|0)>=(e|0))break a}m=l;e=j<<24>>24==3?e:l}else m=0;while(0);if((m|0)>=(e+ -1|0)){c[f+12>>2]=d;c[f+8>>2]=e;q=e;i=g;return q|0}od(f,f+4|0,e+32|0);j=c[f>>2]|0;if(!j){q=-12;i=g;return q|0}ce(j|0,d|0,m|0)|0;o=m+2|0;b:do if((o|0)<(e|0)){l=b+4384|0;b=b+4380|0;n=m;c:while(1){p=d+o|0;q=a[p>>0]|0;do if((q&255)<=3){p=a[d+m>>0]|0;if(!(p<<24>>24))if(!(a[d+(m+1)>>0]|0)){if(q<<24>>24!=3){e=m;break b}o=n+1|0;a[j+n>>0]=0;n=n+2|0;a[j+o>>0]=0;m=m+3|0;q=(c[k>>2]|0)+1|0;c[k>>2]=q;p=c[l>>2]|0;if((p|0)<(q|0)){p=p<<1;c[l>>2]=p;md(b,p,4)|0;p=c[b>>2]|0;if(!p){f=-12;break c}}else{p=c[b>>2]|0;if(!p)break}c[p+((c[k>>2]|0)+ -1<<2)>>2]=o}else{p=0;h=26}else h=26}else{a[j+n>>0]=a[d+m>>0]|0;a[j+(n+1)>>0]=a[d+(m+1)>>0]|0;p=a[p>>0]|0;n=n+2|0;m=o;h=26}while(0);if((h|0)==26){h=0;a[j+n>>0]=p;n=n+1|0;m=m+1|0}o=m+2|0;if((o|0)>=(e|0)){h=15;break b}}i=g;return f|0}else{n=m;h=15}while(0);if((h|0)==15)if((m|0)<(e|0)){h=e+n|0;k=m;while(1){a[j+n>>0]=a[d+k>>0]|0;k=k+1|0;if((k|0)==(e|0))break;else n=n+1|0}n=h-m|0}else e=m;h=j+n+0|0;d=h+32|0;do{a[h>>0]=0;h=h+1|0}while((h|0)<(d|0));c[f+12>>2]=j;c[f+8>>2]=n;q=e;i=g;return q|0}function Lb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;e=i;f=b+60|0;d=c[f>>2]|0;$c();cc();f=c[f>>2]|0;c[f+4>>2]=b;g=nd(31328)|0;c[f+136>>2]=g;if((((g|0)!=0?(c[f+72>>2]=g,c[f+8>>2]=f,g=hd(199)|0,c[f+152>>2]=g,(g|0)!=0):0)?(g=xd()|0,c[f+164>>2]=g,(g|0)!=0):0)?(h=xd()|0,c[f+2524>>2]=h,(h|0)!=0):0){c[f+2528>>2]=h;c[f+2592>>2]=2147483647;a[f+4469>>0]=1;c[f+2584>>2]=0;c[d+4368>>2]=0;c[d+4520>>2]=0;f=b+808|0;if(!(c[f>>2]&2))a[d+141>>0]=1;else a[d+141>>0]=c[b+800>>2];if((c[f>>2]&1|0)!=0?(c[b+800>>2]|0)>1:0){a[d+140>>0]=1;h=0;i=e;return h|0}a[d+140>>0]=2;h=0;i=e;return h|0}Nb(b)|0;h=-12;i=e;return h|0}function Mb(f,g,h,j){f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0,$a=0;k=i;i=i+16|0;m=k+8|0;n=k;l=c[f+60>>2]|0;f=j+28|0;J=c[f>>2]|0;if(!J){g=bc(l,g,1)|0;if((g|0)<0){Za=g;i=k;return Za|0}c[h>>2]=g;Za=0;i=k;return Za|0}q=l+2520|0;c[q>>2]=0;I=c[j+24>>2]|0;c[q>>2]=0;F=l+2584|0;z=l+2588|0;c[z>>2]=c[F>>2];c[F>>2]=0;v=l+4408|0;c[v>>2]=0;a:do if((J|0)>3){G=l+4470|0;E=l+4412|0;y=l+4404|0;u=l+4388|0;B=l+4396|0;w=l+4392|0;C=l+4384|0;x=l+4380|0;j=l+4376|0;t=l+136|0;s=l+2512|0;H=l+4480|0;while(1){A=(a[G>>0]|0)==0;if(A){while(1){K=I+1|0;if(((a[I>>0]|0)==0?(a[K>>0]|0)==0:0)?(a[I+2>>0]|0)==1:0)break;if((J|0)<5){p=-1094995529;o=180;break a}I=K;J=J+ -1|0}I=I+3|0;L=0;J=J+ -3|0}else{K=c[H>>2]|0;if((K|0)>0){M=0;L=0;do{M=d[I+L>>0]|M<<8;L=L+1|0}while((L|0)!=(K|0));L=M}else L=0;J=J-K|0;if((L|0)>(J|0)){p=-1094995529;o=180;break a}I=I+K|0}A=A?J:L;K=c[E>>2]|0;M=c[v>>2]|0;if((K|0)<(M+1|0)){K=K+1|0;L=ld(c[y>>2]|0,K,16)|0;if(!L){p=-12;o=180;break a}c[y>>2]=L;M=c[E>>2]|0;ae(L+(M<<4)|0,0,K-M<<4|0)|0;md(u,K,4)|0;md(B,K,4)|0;md(w,K,4)|0;M=c[B>>2]|0;c[M+(c[E>>2]<<2)>>2]=1024;M=pd(c[M+(c[E>>2]<<2)>>2]|0,4)|0;c[(c[w>>2]|0)+(c[E>>2]<<2)>>2]=M;c[E>>2]=K;M=c[v>>2]|0}c[C>>2]=c[(c[B>>2]|0)+(M<<2)>>2];c[x>>2]=c[(c[w>>2]|0)+(M<<2)>>2];L=c[y>>2]|0;K=Kb(l,I,A,L+(M<<4)|0)|0;c[(c[u>>2]|0)+(c[v>>2]<<2)>>2]=c[j>>2];c[(c[B>>2]|0)+(c[v>>2]<<2)>>2]=c[C>>2];Ya=c[x>>2]|0;Za=c[v>>2]|0;c[v>>2]=Za+1;c[(c[w>>2]|0)+(Za<<2)>>2]=Ya;if((K|0)<0){p=K;o=180;break a}Ya=c[t>>2]|0;Wa=c[L+(M<<4)+12>>2]|0;Xa=c[L+(M<<4)+8>>2]|0;Xa=Xa>>>0>268435455?-8:Xa<<3;Za=Xa>>>0>2147483639|(Wa|0)==0;Xa=Za?0:Xa;Wa=Za?0:Wa;A=Za?-1094995529:0;c[Ya+204>>2]=Wa;c[Ya+216>>2]=Xa;c[Ya+220>>2]=Xa+8;c[Ya+208>>2]=Wa+(Xa>>3);c[Ya+212>>2]=0;if(Za){p=A;o=180;break a}Qb(l)|0;if(((c[s>>2]|0)+ -36|0)>>>0<2)c[F>>2]=1;J=J-K|0;if((J|0)<=3)break;else I=I+K|0}if((c[v>>2]|0)>0){ka=l+4|0;za=l+1448|0;aa=l+2046|0;Z=l+1428|0;ya=l+204|0;pa=l+200|0;Ha=l+1449|0;Ia=l+1432|0;Ma=l+1436|0;Na=l+2580|0;Fa=l+156|0;Ba=l+1440|0;H=l+1450|0;K=l+1620|0;oa=l+2572|0;J=l+2516|0;L=l+2576|0;V=l+2056|0;W=l+2057|0;M=l+2058|0;O=l+2052|0;N=l+2048|0;Ka=l+2068|0;R=l+2072|0;P=l+2076|0;S=l+2080|0;X=l+2061|0;U=l+2084|0;T=l+2088|0;Y=l+2062|0;I=l+1451|0;La=l+2108|0;Ga=l+2112|0;Ja=l+2500|0;Aa=l+2592|0;la=l+2604|0;ma=l+4416|0;B=m+4|0;qa=l+4320|0;ta=l+2596|0;ra=l+2600|0;ua=l+4324|0;va=l+4344|0;wa=l+4348|0;xa=l+4328|0;na=l+160|0;Ea=l+140|0;Ca=l+164|0;_=l+2096|0;Q=l+2100|0;E=l+2104|0;F=l+141|0;G=l+4368|0;ca=l+2504|0;ba=l+2508|0;ea=l+4332|0;da=l+4336|0;fa=l+4340|0;ha=l+4352|0;ga=l+4316|0;ia=l+2608|0;Oa=l+196|0;Pa=l+4364|0;ja=l+168|0;C=0;b:while(1){c[j>>2]=c[(c[u>>2]|0)+(C<<2)>>2];c[x>>2]=c[(c[w>>2]|0)+(C<<2)>>2];Ya=c[y>>2]|0;Xa=c[Ya+(C<<4)+12>>2]|0;Ya=c[Ya+(C<<4)+8>>2]|0;Za=c[t>>2]|0;Ya=Ya>>>0>268435455?-8:Ya<<3;Qa=Ya>>>0>2147483639|(Xa|0)==0;Ya=Qa?0:Ya;Xa=Qa?0:Xa;c[Za+204>>2]=Xa;c[Za+216>>2]=Ya;c[Za+220>>2]=Ya+8;c[Za+208>>2]=Xa+(Ya>>3);c[Za+212>>2]=0;c:do if(Qa){r=Qa?-1094995529:0;o=178}else{Qa=Qb(l)|0;d:do if((Qa|0)>=0){if(!Qa)break c;switch(c[s>>2]|0){case 9:case 8:case 7:case 6:case 21:case 20:case 19:case 18:case 17:case 16:case 5:case 4:case 3:case 2:case 0:case 1:{Qa=c[t>>2]|0;Ra=Qa+204|0;Za=(dd(Ra)|0)&255;a[za>>0]=Za;Sa=c[s>>2]|0;if(!((Sa+ -16|0)>>>0>4|Za<<24>>24==0)?(b[Pa>>1]=(e[Pa>>1]|0)+1&255,c[Aa>>2]=2147483647,(Sa+ -19|0)>>>0<2):0){_b(l);Sa=c[s>>2]|0}a[aa>>0]=0;if((Sa+ -16|0)>>>0<8)a[aa>>0]=dd(Ra)|0;Sa=fd(Ra)|0;c[Z>>2]=Sa;if(Sa>>>0>255){p=A;o=180;break a}Sa=c[l+(Sa<<2)+400>>2]|0;if(!Sa){p=A;o=180;break a}if(!(a[za>>0]|0)){Va=c[Sa+4>>2]|0;if((c[ya>>2]|0)!=(Va|0)){p=A;o=180;break a}}else Va=c[Sa+4>>2]|0;c[ya>>2]=Va;Ta=c[s>>2]|0;Ua=(Ta|0)==21;if(Ua?(c[z>>2]|0)==1:0)a[aa>>0]=1;Sa=c[pa>>2]|0;Va=c[(c[l+(c[Va>>2]<<2)+272>>2]|0)+4>>2]|0;if((Sa|0)!=(Va|0)){c[pa>>2]=Va;e:do if(Sa){if((Ta+ -16|0)>>>0>7|Ua)break;do if((c[Va+13120>>2]|0)==(c[Sa+13120>>2]|0)){if((c[Va+13124>>2]|0)!=(c[Sa+13124>>2]|0))break;if((c[Va+76+(((c[Va+72>>2]|0)+ -1|0)*12|0)>>2]|0)==(c[Sa+(((c[Sa+72>>2]|0)+ -1|0)*12|0)+76>>2]|0))break e}while(0);a[aa>>0]=0}while(0);_b(l);Sa=c[pa>>2]|0;Pb(l);Ua=c[Sa+13064>>2]|0;Va=Sa+13120|0;$a=c[Va>>2]|0;Wa=Sa+13124|0;_a=c[Wa>>2]|0;Ua=$((_a>>Ua)+1|0,($a>>Ua)+1|0)|0;Ta=$(c[Sa+13132>>2]|0,c[Sa+13128>>2]|0)|0;Za=Sa+13156|0;Ya=Sa+13160|0;Xa=$(c[Ya>>2]|0,c[Za>>2]|0)|0;c[ta>>2]=($a>>2)+1;c[ra>>2]=(_a>>2)+1;c[ca>>2]=qd(Ta,148)|0;_a=qd(Ta,8)|0;c[ba>>2]=_a;if((c[ca>>2]|0)==0|(_a|0)==0){o=71;break b}_a=Sa+13144|0;$a=Sa+13140|0;c[ea>>2]=hd($(c[$a>>2]|0,c[_a>>2]|0)|0)|0;$a=pd(c[_a>>2]|0,c[$a>>2]|0)|0;c[da>>2]=$a;if((c[ea>>2]|0)==0|($a|0)==0){o=71;break b}c[va>>2]=pd(c[Sa+13148>>2]|0,c[Sa+13152>>2]|0)|0;c[fa>>2]=nd(Xa)|0;Xa=hd($((c[Ya>>2]|0)+1|0,(c[Za>>2]|0)+1|0)|0)|0;c[wa>>2]=Xa;if(!(c[fa>>2]|0)){o=71;break b}if((c[va>>2]|0)==0|(Xa|0)==0){o=71;break b}c[ha>>2]=hd(Ta)|0;c[xa>>2]=pd(Ua,4)|0;$a=pd(Ua,1)|0;c[ga>>2]=$a;if(!$a){o=71;break b}if(!(c[ha>>2]|0)){o=71;break b}if(!(c[xa>>2]|0)){o=71;break b}c[qa>>2]=qd(c[ta>>2]|0,c[ra>>2]|0)|0;$a=qd(c[ta>>2]|0,c[ra>>2]|0)|0;c[ua>>2]=$a;if((c[qa>>2]|0)==0|($a|0)==0){o=71;break b}$a=c[ka>>2]|0;c[$a+124>>2]=c[Va>>2];c[$a+128>>2]=c[Wa>>2];c[$a+116>>2]=c[Sa+12>>2];c[$a+120>>2]=c[Sa+16>>2];c[$a+136>>2]=c[Sa+60>>2];c[$a+172>>2]=c[Sa+(((c[Sa+72>>2]|0)+ -1|0)*12|0)+80>>2];$a=Sa+160|0;c[m+0>>2]=c[$a+0>>2];c[m+4>>2]=c[$a+4>>2];if(!(c[Sa+176>>2]|0)){Ta=c[ka>>2]|0;c[Ta+392>>2]=1}else{Ta=c[ka>>2]|0;c[Ta+392>>2]=(c[Sa+184>>2]|0)!=0?2:1}if(!(c[Sa+188>>2]|0)){c[Ta+380>>2]=2;c[Ta+384>>2]=2;c[Ta+388>>2]=2}else{c[Ta+380>>2]=d[Sa+192>>0];c[Ta+384>>2]=d[Sa+193>>0];c[Ta+388>>2]=d[Sa+194>>0]}dc(ia,c[Sa+52>>2]|0);if(a[Sa+12941>>0]|0){Ta=c[pa>>2]|0;Ua=(c[Ta+4>>2]|0)!=0?3:1;$a=(1<>2])+2|0;$a=$($a,$a)|0;c[ja>>2]=hd($a<>2])|0;Ta=0;do{$a=c[pa>>2]|0;_a=c[$a+13124>>2]>>c[$a+(Ta<<2)+13180>>2];Za=$(c[$a+13120>>2]>>c[$a+(Ta<<2)+13168>>2]<<1,c[$a+13132>>2]|0)|0;c[l+(Ta<<2)+172>>2]=hd(Za<>2])|0;$a=c[pa>>2]|0;_a=$(_a<<1,c[$a+13128>>2]|0)|0;c[l+(Ta<<2)+184>>2]=hd(_a<>2])|0;Ta=Ta+1|0}while((Ta|0)<(Ua|0))}c[pa>>2]=Sa;c[Oa>>2]=c[(c[l+(c[Sa>>2]<<2)+208>>2]|0)+4>>2];b[Pa>>1]=(e[Pa>>1]|0)+1&255;c[Aa>>2]=2147483647}$a=c[ka>>2]|0;c[$a+832>>2]=d[Sa+302>>0];c[$a+836>>2]=d[Sa+335>>0];a[Ha>>0]=0;do if(!(a[za>>0]|0)){if(a[(c[ya>>2]|0)+41>>0]|0){a[Ha>>0]=dd(Ra)|0;Sa=c[pa>>2]|0}Sa=($(c[Sa+13128>>2]<<1,c[Sa+13132>>2]|0)|0)+ -2|0;Ta=Sa>>>0>65535;Sa=Ta?Sa>>>16:Sa;Ta=Ta?16:0;if(Sa&65280){Ta=Ta|8;Sa=Sa>>>8}Sa=ad(Ra,(d[4680+Sa>>0]|0)+Ta|0)|0;c[Ia>>2]=Sa;$a=c[pa>>2]|0;if(Sa>>>0>=($(c[$a+13132>>2]|0,c[$a+13128>>2]|0)|0)>>>0){p=A;o=180;break a}if(a[Ha>>0]|0)if(!(a[Fa>>0]|0)){p=A;o=180;break a}else break;else{c[Ma>>2]=Sa;c[Na>>2]=(c[Na>>2]|0)+1;o=82;break}}else{c[Ma>>2]=0;c[Ia>>2]=0;c[Na>>2]=0;a[Fa>>0]=0;o=82}while(0);f:do if((o|0)==82){o=0;a[Fa>>0]=0;if((c[(c[ya>>2]|0)+1624>>2]|0)>0){Sa=0;do{cd(Ra,1);Sa=Sa+1|0}while((Sa|0)<(c[(c[ya>>2]|0)+1624>>2]|0))}Sa=fd(Ra)|0;c[Ba>>2]=Sa;if(Sa>>>0>=3){p=A;o=180;break a}if(!((Sa|0)==2?1:((c[s>>2]|0)+ -16|0)>>>0>7)){p=A;o=180;break a}a[H>>0]=1;if(a[(c[ya>>2]|0)+39>>0]|0)a[H>>0]=dd(Ra)|0;if(a[(c[pa>>2]|0)+8>>0]|0)a[I>>0]=ad(Ra,2)|0;if(((c[s>>2]|0)+ -19|0)>>>0>=2){o=91;break b}c[K>>2]=0;c[oa>>2]=0;if(!(c[J>>2]|0))c[L>>2]=0;do if(a[(c[pa>>2]|0)+12941>>0]|0){a[V>>0]=dd(Ra)|0;if(!(c[(c[pa>>2]|0)+4>>2]|0)){a[W>>0]=0;a[M>>0]=0;break}else{$a=(dd(Ra)|0)&255;a[M>>0]=$a;a[W>>0]=$a;break}}else{a[V>>0]=0;a[W>>0]=0;a[M>>0]=0}while(0);c[O>>2]=0;c[N>>2]=0;c[Ka>>2]=gd(Ra)|0;Sa=c[ya>>2]|0;if(!(a[Sa+36>>0]|0)){c[R>>2]=0;c[P>>2]=0}else{c[R>>2]=gd(Ra)|0;c[P>>2]=gd(Ra)|0;Sa=c[ya>>2]|0}if(!(a[Sa+1631>>0]|0))a[S>>0]=0;else{a[S>>0]=dd(Ra)|0;Sa=c[ya>>2]|0}g:do if(!(a[Sa+55>>0]|0)){a[X>>0]=0;c[U>>2]=0;c[T>>2]=0}else{do if(a[Sa+56>>0]|0){if(!(dd(Ra)|0)){Sa=c[ya>>2]|0;break}$a=(dd(Ra)|0)&255;a[X>>0]=$a;if($a<<24>>24)break g;c[U>>2]=(gd(Ra)|0)<<1;c[T>>2]=(gd(Ra)|0)<<1;break g}while(0);a[X>>0]=a[Sa+57>>0]|0;c[U>>2]=c[Sa+60>>2];c[T>>2]=c[Sa+64>>2]}while(0);Sa=a[(c[ya>>2]|0)+54>>0]|0;h:do if(Sa<<24>>24){do if(!(a[V>>0]|0)){if(a[W>>0]|0)break;if(a[X>>0]|0)break h}while(0);a[Y>>0]=dd(Ra)|0;break f}while(0);a[Y>>0]=Sa}while(0);c[La>>2]=0;$a=c[ya>>2]|0;if(!((a[$a+42>>0]|0)==0?(a[$a+43>>0]|0)==0:0))o=122;i:do if((o|0)==122){o=0;$a=fd(Ra)|0;c[La>>2]=$a;if(($a|0)<=0){c[G>>2]=0;break}Sa=(fd(Ra)|0)+1|0;Ta=Sa>>4;Sa=Sa&15;kd(_);kd(Q);kd(E);c[_>>2]=pd(c[La>>2]|0,4)|0;c[Q>>2]=pd(c[La>>2]|0,4)|0;Ua=pd(c[La>>2]|0,4)|0;c[E>>2]=Ua;if(!(c[_>>2]|0)){o=127;break b}if((c[Q>>2]|0)==0|(Ua|0)==0){o=127;break b}if((c[La>>2]|0)>0){Va=(Ta|0)>0;Wa=(Sa|0)==0;Ua=0;do{if(Va){Xa=0;Ya=0;do{Ya=(ad(Ra,16)|0)+(Ya<<16)|0;Xa=Xa+1|0}while((Xa|0)!=(Ta|0))}else Ya=0;if(!Wa)Ya=(ad(Ra,Sa)|0)+(Ya<>2]|0)+(Ua<<2)>>2]=Ya+1;Ua=Ua+1|0}while((Ua|0)<(c[La>>2]|0))}do if((d[F>>0]|0)>1){$a=c[ya>>2]|0;if((c[$a+48>>2]|0)<=1?(c[$a+44>>2]|0)<=1:0)break;c[G>>2]=0;a[F>>0]=1;break i}while(0);c[G>>2]=0}while(0);Sa=c[ya>>2]|0;if(a[Sa+1628>>0]|0){Sa=fd(Ra)|0;_a=be(Sa|0,0,3)|0;Ya=D;$a=(c[Qa+216>>2]|0)-(c[Qa+212>>2]|0)|0;Za=(($a|0)<0)<<31>>31;if((Ya|0)>(Za|0)|(Ya|0)==(Za|0)&_a>>>0>$a>>>0){p=A;o=180;break a}if(Sa){Ta=0;do{cd(Ra,8);Ta=Ta+1|0}while((Ta|0)!=(Sa|0))}Sa=c[ya>>2]|0}Ra=(c[Sa+16>>2]|0)+26+(c[Ka>>2]|0)|0;a[Ga>>0]=Ra;Ra=Ra<<24;if((Ra|0)>855638016){p=A;o=180;break a}if((Ra>>24|0)<(0-(c[(c[pa>>2]|0)+13192>>2]|0)|0)){p=A;o=180;break a}$a=c[Ia>>2]|0;c[Ja>>2]=$a;if(($a|0)==0?(a[Ha>>0]|0)!=0:0){p=A;o=180;break a}if(((c[Qa+216>>2]|0)-(c[Qa+212>>2]|0)|0)<0){p=A;o=180;break a}a[(c[t>>2]|0)+203>>0]=(a[Ha>>0]|0)==0&1;if(!(a[(c[ya>>2]|0)+22>>0]|0))a[(c[t>>2]|0)+272>>0]=a[Ga>>0]|0;a[Fa>>0]=1;a[(c[t>>2]|0)+302>>0]=0;a[(c[t>>2]|0)+303>>0]=0;Ra=c[Aa>>2]|0;Qa=c[s>>2]|0;j:do if((Ra|0)==2147483647)switch(Qa|0){case 18:case 16:case 17:case 21:{Ra=c[oa>>2]|0;c[Aa>>2]=Ra;break j};case 20:case 19:{c[Aa>>2]=-2147483648;Ra=-2147483648;break j};default:{Ra=2147483647;break j}}while(0);do if((Qa+ -8|0)>>>0<2){if((c[oa>>2]|0)<=(Ra|0)){c[la>>2]=0;break c}if((Qa|0)!=9)break;c[Aa>>2]=-2147483648}while(0);k:do if(!(a[za>>0]|0)){if(!(c[q>>2]|0)){Qa=0;break d}}else{Ra=c[t>>2]|0;_a=c[pa>>2]|0;Qa=c[_a+13064>>2]|0;$a=c[_a+13120>>2]>>Qa;Qa=(c[_a+13124>>2]>>Qa)+1|0;ae(c[qa>>2]|0,0,$(c[ra>>2]|0,c[ta>>2]|0)|0)|0;ae(c[ua>>2]|0,0,$(c[ra>>2]|0,c[ta>>2]|0)|0)|0;_a=c[pa>>2]|0;ae(c[va>>2]|0,0,$(c[_a+13152>>2]|0,c[_a+13148>>2]|0)|0)|0;_a=c[pa>>2]|0;ae(c[wa>>2]|0,0,$((c[_a+13160>>2]|0)+1|0,(c[_a+13156>>2]|0)+1|0)|0)|0;ae(c[xa>>2]|0,-1,$(($a<<2)+4|0,Qa)|0)|0;c[la>>2]=0;c[ma>>2]=c[s>>2];Qa=c[ya>>2]|0;if(a[Qa+42>>0]|0)c[Ra+312>>2]=c[c[Qa+1648>>2]>>2]<>2]|0)+13080>>2];Qa=ac(l,na,c[oa>>2]|0)|0;do if((Qa|0)>=0){c[(c[c[q>>2]>>2]|0)+80>>2]=((c[s>>2]|0)+ -16|0)>>>0<8&1;c[(c[na>>2]|0)+84>>2]=3-(c[Ba>>2]|0);zd(c[Ca>>2]|0);Qa=bc(l,c[Ca>>2]|0,0)|0;if((Qa|0)<0)break;break k}while(0);if(!(c[q>>2]|0)){o=167;break b}c[q>>2]=0;if((Qa|0)<0){p=A;break a}}while(0);if((c[s>>2]|0)!=(c[ma>>2]|0)){p=A;o=180;break a}c[m>>2]=0;c[B>>2]=1;Qa=c[ka>>2]|0;Da[c[Qa+816>>2]&1](Qa,1,m,n,1,4)|0;Qa=c[n>>2]|0;$a=c[pa>>2]|0;if((Qa|0)>=($(c[$a+13132>>2]|0,c[$a+13128>>2]|0)|0))c[la>>2]=1;if((Qa|0)<0)break d;else break c};case 37:case 36:{b[Pa>>1]=(e[Pa>>1]|0)+1&255;c[Aa>>2]=2147483647;break c};case 48:{Qa=Fc(l)|0;if((Qa|0)<0)break d;else break c};case 34:{Qa=Gc(l)|0;if((Qa|0)<0)break d;else break c};case 40:case 39:{Qa=Ic(l)|0;if((Qa|0)<0)break d;else break c};default:break c}}while(0);r=(c[(c[ka>>2]|0)+688>>2]&8|0)==0?0:Qa;o=178}while(0);if((o|0)==178?(o=0,(r|0)<0):0){p=A;o=180;break a}C=C+1|0;if((C|0)>=(c[v>>2]|0)){p=A;o=180;break a}}if((o|0)==71){Pb(l);Pb(l);c[pa>>2]=0;p=A;o=180;break}else if((o|0)==91)sa();else if((o|0)==127){c[La>>2]=0;p=A;o=180;break}else if((o|0)==167){c[q>>2]=0;p=A;break}}else{p=A;o=180}}else{p=0;o=180}while(0);if((p|0)<0){$a=p;i=k;return $a|0}m=l+2604|0;if(c[m>>2]|0)c[m>>2]=0;l=c[l+164>>2]|0;if(c[l+304>>2]|0){Ad(g,l);c[h>>2]=1}$a=c[f>>2]|0;i=k;return $a|0}function Nb(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;e=c[b+60>>2]|0;Pb(e);b=e+4412|0;f=e+4392|0;if((c[b>>2]|0)>0){g=0;do{kd((c[f>>2]|0)+(g<<2)|0);g=g+1|0}while((g|0)<(c[b>>2]|0))}kd(e+4396|0);kd(e+4388|0);kd(f);kd(e+152|0);kd(e+168|0);kd(e+172|0);kd(e+184|0);kd(e+176|0);kd(e+188|0);kd(e+180|0);kd(e+192|0);yd(e+164|0);g=e+2524|0;Zb(e,g,-1);yd(g);g=e+208|0;f=0;do{wd(g+(f<<2)|0);f=f+1|0}while((f|0)!=16);g=e+272|0;f=0;do{wd(g+(f<<2)|0);f=f+1|0}while((f|0)!=32);f=e+400|0;g=0;do{wd(f+(g<<2)|0);g=g+1|0}while((g|0)!=256);c[e+200>>2]=0;c[e+204>>2]=0;c[e+196>>2]=0;wd(e+1424|0);kd(e+2096|0);kd(e+2100|0);kd(e+2104|0);h=e+141|0;l=a[h>>0]|0;f=e+72|0;if((l&255)>1){g=e+8|0;j=1;do{k=f+(j<<2)|0;if(c[k>>2]|0){kd(k);kd(g+(j<<2)|0);l=a[h>>0]|0}j=j+1|0}while((j|0)<(l&255|0))}g=e+136|0;if((c[g>>2]|0)==(c[f>>2]|0))c[g>>2]=0;kd(f);f=e+4404|0;if((c[b>>2]|0)<=0){kd(f);c[b>>2]=0;i=d;return 0}e=0;do{kd((c[f>>2]|0)+(e<<4)|0);e=e+1|0}while((e|0)<(c[b>>2]|0));kd(f);c[b>>2]=0;i=d;return 0}function Ob(a){a=a|0;var b=0;b=i;a=c[a+60>>2]|0;$b(a);c[a+2592>>2]=2147483647;i=b;return}function Pb(a){a=a|0;var b=0;b=i;kd(a+2504|0);kd(a+2508|0);kd(a+4332|0);kd(a+4336|0);kd(a+4340|0);kd(a+4344|0);kd(a+4348|0);kd(a+4316|0);kd(a+4328|0);kd(a+4352|0);kd(a+4320|0);kd(a+4324|0);kd(a+2096|0);kd(a+2104|0);kd(a+2100|0);i=b;return}function Qb(a){a=a|0;var b=0,d=0,e=0;b=i;d=(c[a+136>>2]|0)+204|0;if(dd(d)|0){e=-1094995529;i=b;return e|0}c[a+2512>>2]=ad(d,6)|0;e=ad(d,6)|0;d=(ad(d,3)|0)+ -1|0;c[a+2516>>2]=d;if((d|0)<0){e=-1094995529;i=b;return e|0}e=(e|0)==0&1;i=b;return e|0}function Rb(e,f){e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0;f=i;h=c[e+60>>2]|0;k=h+200|0;E=c[k>>2]|0;e=1<>2];l=h+204|0;n=c[l>>2]|0;A=c[(c[n+1668>>2]|0)+(c[h+2500>>2]<<2)>>2]|0;m=(a[h+1449>>0]|0)==0;if(!A)if(m)g=4;else{W=-1094995529;i=f;return W|0}else if(!m){m=h+4328|0;r=h+1436|0;if((c[(c[m>>2]|0)+(c[(c[n+1672>>2]|0)+(A+ -1<<2)>>2]<<2)>>2]|0)!=(c[r>>2]|0)){W=-1094995529;i=f;return W|0}}else g=4;if((g|0)==4){m=h+4328|0;r=h+1436|0}q=e+ -1|0;s=h+136|0;p=h+2504|0;y=h+2056|0;o=h+2057|0;w=h+2084|0;x=h+2508|0;v=h+2088|0;u=h+2062|0;t=h+4352|0;z=0;n=0;do{if((A|0)>=(c[E+13136>>2]|0))break;G=c[l>>2]|0;B=c[(c[G+1672>>2]|0)+(A<<2)>>2]|0;J=E+13120|0;I=E+13080|0;H=c[I>>2]|0;n=q+(c[J>>2]|0)>>H;z=((B|0)%(n|0)|0)<>2]|0;H=1<>2]|0;D=B-F|0;c[(c[m>>2]|0)+(B<<2)>>2]=F;do if(!(a[G+43>>0]|0)){if(!(a[G+42>>0]|0)){c[C+312>>2]=c[J>>2];G=E;break}if((A|0)!=0?(W=c[G+1676>>2]|0,(c[W+(A<<2)>>2]|0)!=(c[W+(A+ -1<<2)>>2]|0)):0){W=c[I>>2]|0;c[C+312>>2]=(c[(c[G+1648>>2]|0)+(c[(c[G+1664>>2]|0)+(z>>W<<2)>>2]<<2)>>2]<>0]=1;G=c[k>>2]|0}else G=E}else{if((z|0)==0?(H+ -1&n|0)==0:0){a[C+203>>0]=1;E=c[k>>2]|0}c[C+312>>2]=c[E+13120>>2];G=E}while(0);E=H+n|0;H=c[G+13124>>2]|0;c[C+316>>2]=(E|0)>(H|0)?H:E;E=C+31312|0;c[E>>2]=0;H=c[l>>2]|0;if(!(a[H+42>>0]|0)){if((B|0)==(F|0)){c[E>>2]=1;F=1}else F=0;if((D|0)<(c[G+13128>>2]|0)){F=F|4;c[E>>2]=F}}else{if((z|0)>0){W=c[H+1676>>2]|0;I=B+ -1|0;if((c[W+(A<<2)>>2]|0)==(c[W+(c[(c[H+1668>>2]|0)+(I<<2)>>2]<<2)>>2]|0))F=0;else{c[E>>2]=2;F=2}W=c[m>>2]|0;if((c[W+(B<<2)>>2]|0)!=(c[W+(I<<2)>>2]|0)){F=F|1;c[E>>2]=F}}else F=0;if((n|0)>0){W=c[H+1676>>2]|0;I=G+13128|0;G=c[I>>2]|0;if((c[W+(A<<2)>>2]|0)!=(c[W+(c[(c[H+1668>>2]|0)+(B-G<<2)>>2]<<2)>>2]|0)){F=F|8;c[E>>2]=F;G=c[I>>2]|0}W=c[m>>2]|0;if((c[W+(B<<2)>>2]|0)!=(c[W+(B-G<<2)>>2]|0)){F=F|4;c[E>>2]=F}}}E=(z|0)>0;if(E&(D|0)>0)G=(F>>>1&1^1)&255;else G=0;a[C+308>>0]=G;if((n|0)>0){if((D|0)<(c[(c[k>>2]|0)+13128>>2]|0))F=0;else F=(F>>>3&1^1)&255;a[C+309>>0]=F;F=c[(c[k>>2]|0)+13128>>2]|0;if((D+1|0)<(F|0))F=0;else{W=c[l>>2]|0;V=c[W+1676>>2]|0;F=(c[V+(A<<2)>>2]|0)==(c[V+(c[(c[W+1668>>2]|0)+(B+1-F<<2)>>2]<<2)>>2]|0)&1}a[C+310>>0]=F;if(E?(j=c[(c[k>>2]|0)+13128>>2]|0,(D|0)>(j|0)):0){D=c[l>>2]|0;W=c[D+1676>>2]|0;D=(c[W+(A<<2)>>2]|0)==(c[W+(c[(c[D+1668>>2]|0)+(B+ -1-j<<2)>>2]<<2)>>2]|0)&1}else D=0}else{a[C+309>>0]=0;a[C+310>>0]=0;D=0}a[C+311>>0]=D;Wa(h,A);D=c[k>>2]|0;E=c[D+13080>>2]|0;F=z>>E;E=n>>E;G=c[s>>2]|0;D=($(c[D+13128>>2]|0,E)|0)+F|0;C=c[p>>2]|0;if((a[y>>0]|0)==0?(a[o>>0]|0)==0:0){M=0;H=0}else{if((F|0)>0?(a[G+308>>0]|0)!=0:0)M=$a(h)|0;else M=0;if((E|0)>0&(M|0)==0)if(!(a[G+309>>0]|0)){M=0;H=0}else{M=0;H=($a(h)|0)!=0}else H=0}I=(c[(c[k>>2]|0)+4>>2]|0)!=0?3:1;L=C+(D*148|0)+143|0;G=C+(D*148|0)+144|0;K=C+(D*148|0)+104|0;J=C+(D*148|0)+108|0;R=(M|0)==0;S=R&(H^1);M=E+ -1|0;O=F+ -1|0;P=0;do{Q=c[l>>2]|0;Q=d[((P|0)==0?Q+1644|0:Q+1645|0)>>0]|0;a:do if(a[h+P+2056>>0]|0){T=(P|0)==2;do if(!T){if(S){U=(bb(h)|0)&255;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}if(!R){U=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;U=a[(c[p>>2]|0)+(U*148|0)+P+142>>0]|0;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}if(H){U=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;U=a[(c[p>>2]|0)+(U*148|0)+P+142>>0]|0;N=C+(D*148|0)+P+142|0;a[N>>0]=U;break}else{a[C+(D*148|0)+P+142>>0]=0;break a}}else{U=a[L>>0]|0;a[G>>0]=U;c[J>>2]=c[K>>2];N=G}while(0);if(U<<24>>24){U=0;do{do if(!S){if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(U<<2)>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(U<<2)>>2];break}else{c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=0;break}}else c[C+(D*148|0)+(P<<4)+(U<<2)>>2]=eb(h)|0;while(0);U=U+1|0}while((U|0)!=4);do if((a[N>>0]|0)==1){T=0;do{do if(c[C+(D*148|0)+(P<<4)+(T<<2)>>2]|0){if(S){c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=fb(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(T<<2)+48>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<4)+(T<<2)+48>>2];break}else{c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=0;break}}else c[C+(D*148|0)+(P<<4)+(T<<2)+48>>2]=0;while(0);T=T+1|0}while((T|0)!=4);if(S){a[C+(D*148|0)+P+96>>0]=db(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;a[C+(D*148|0)+P+96>>0]=a[(c[p>>2]|0)+(W*148|0)+P+96>>0]|0;break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;a[C+(D*148|0)+P+96>>0]=a[(c[p>>2]|0)+(W*148|0)+P+96>>0]|0;break}else{a[C+(D*148|0)+P+96>>0]=0;break}}else if(!T){if(S){c[C+(D*148|0)+(P<<2)+100>>2]=gb(h)|0;break}if(!R){W=($(c[(c[k>>2]|0)+13128>>2]|0,E)|0)+O|0;c[C+(D*148|0)+(P<<2)+100>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<2)+100>>2];break}if(H){W=($(c[(c[k>>2]|0)+13128>>2]|0,M)|0)+F|0;c[C+(D*148|0)+(P<<2)+100>>2]=c[(c[p>>2]|0)+(W*148|0)+(P<<2)+100>>2];break}else{c[C+(D*148|0)+(P<<2)+100>>2]=0;break}}while(0);b[C+(D*148|0)+(P*10|0)+112>>1]=0;T=0;do{W=c[C+(D*148|0)+(P<<4)+(T<<2)>>2]|0;V=T;T=T+1|0;U=C+(D*148|0)+(P*10|0)+(T<<1)+112|0;b[U>>1]=W;if((a[N>>0]|0)==2){if((V|0)>1){W=0-W|0;b[U>>1]=W}}else if(c[C+(D*148|0)+(P<<4)+(V<<2)+48>>2]|0){W=0-W|0;b[U>>1]=W}b[U>>1]=W<<16>>16<>0]=0;while(0);P=P+1|0}while((P|0)<(I|0));C=c[x>>2]|0;c[C+(B<<3)>>2]=c[w>>2];c[C+(B<<3)+4>>2]=c[v>>2];a[(c[t>>2]|0)+B>>0]=a[u>>0]|0;C=Sb(h,z,n,c[(c[k>>2]|0)+13080>>2]|0,0)|0;if((C|0)<0){g=108;break}A=A+1|0;Va(h,A);Fb(h,z,n,e);E=c[k>>2]|0}while((C|0)!=0);if((g|0)==108){c[(c[m>>2]|0)+(B<<2)>>2]=-1;W=C;i=f;return W|0}if((z+e|0)<(c[E+13120>>2]|0)){W=A;i=f;return W|0}if((n+e|0)<(c[E+13124>>2]|0)){W=A;i=f;return W|0}Db(h,z,n,e);W=A;i=f;return W|0}function Sb(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0;j=i;i=i+32|0;z=j;B=j+20|0;A=b+136|0;r=c[A>>2]|0;l=1<>2]|0;q=b+204|0;t=c[q>>2]|0;p=(1<<(c[s+13080>>2]|0)-(c[t+24>>2]|0))+ -1|0;c[r+31232>>2]=h;k=l+e|0;if(((k|0)<=(c[s+13120>>2]|0)?(l+f|0)<=(c[s+13124>>2]|0):0)?(c[s+13064>>2]|0)>>>0>>0:0){s=nb(b,h,e,f)|0;t=c[q>>2]|0}else s=(c[s+13064>>2]|0)>>>0>>0&1;if((a[t+22>>0]|0)!=0?((c[(c[m>>2]|0)+13080>>2]|0)-(c[t+24>>2]|0)|0)>>>0<=g>>>0:0){a[r+300>>0]=0;c[r+280>>2]=0}if((a[b+2080>>0]|0)!=0?((c[(c[m>>2]|0)+13080>>2]|0)-(d[(c[q>>2]|0)+1632>>0]|0)|0)>>>0<=g>>>0:0)a[r+301>>0]=0;if(s){o=l>>1;n=o+e|0;q=o+f|0;g=g+ -1|0;h=h+1|0;s=Sb(b,e,f,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}if(s){if((n|0)<(c[(c[m>>2]|0)+13120>>2]|0)){s=Sb(b,n,f,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}if(s){if((q|0)<(c[(c[m>>2]|0)+13124>>2]|0)){s=Sb(b,e,q,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}if(s){X=c[m>>2]|0;if((n|0)<(c[X+13120>>2]|0)?(q|0)<(c[X+13124>>2]|0):0){s=Sb(b,n,q,g,h)|0;if((s|0)<0){X=s;i=j;return X|0}}}else s=0}else s=0}else s=0;if((p&k|0)==0?(p&l+f|0)==0:0)c[r+276>>2]=a[r+272>>0];if(!s){X=0;i=j;return X|0}k=c[m>>2]|0;if((n+o|0)<(c[k+13120>>2]|0))k=1;else k=(q+o|0)<(c[k+13124>>2]|0);X=k&1;i=j;return X|0}p=c[A>>2]|0;s=c[m>>2]|0;r=c[s+13064>>2]|0;h=c[s+13140>>2]|0;s=1<<(c[s+13080>>2]|0)-(c[(c[q>>2]|0)+24>>2]|0);c[p+31236>>2]=e;c[p+31240>>2]=f;x=p+31252|0;a[x>>0]=1;v=p+31244|0;c[v>>2]=1;E=p+31248|0;c[E>>2]=0;w=p+31254|0;a[w>>0]=0;y=p+31253|0;a[y>>0]=0;t=($(f>>r,h)|0)+(e>>r)|0;H=b+4332|0;a[(c[H>>2]|0)+t>>0]=0;X=p+31268|0;a[X>>0]=1;a[X+1>>0]=1;a[X+2>>0]=1;a[X+3>>0]=1;r=l>>r;s=s+ -1|0;if(a[(c[q>>2]|0)+40>>0]|0){X=(ib(b)|0)&255;a[p+31256>>0]=X;if(X<<24>>24)Tb(b,e,f,g)}else a[p+31256>>0]=0;u=(r|0)>0;if(u){G=t;F=0;while(1){ae((c[H>>2]|0)+G|0,0,r|0)|0;F=F+1|0;if((F|0)==(r|0))break;else G=G+h|0}}if((c[v>>2]|0)==1?(c[(c[m>>2]|0)+13064>>2]|0)!=(g|0):0)D=c[E>>2]|0;else{F=ob(b,g)|0;c[E>>2]=F;E=c[v>>2]|0;if((F|0)==3)G=(E|0)==1&1;else G=0;a[w>>0]=G;if((E|0)==1)D=F;else sa()}if((((D|0)==0?(C=c[m>>2]|0,(c[C+68>>2]|0)!=0):0)?(c[C+13048>>2]|0)>>>0<=g>>>0:0)?(c[C+13052>>2]|0)>>>0>=g>>>0:0){C=(pb(b)|0)&255;a[y>>0]=C}else C=a[y>>0]|0;do if(!(C<<24>>24)){C=c[A>>2]|0;E=(c[C+31248>>2]|0)==3;D=E?2:1;H=0;do{F=H<<1;G=0;do{a[B+(G+F)>>0]=qb(b)|0;G=G+1|0}while((G|0)<(D|0));H=H+1|0}while((H|0)<(D|0));Q=l>>(E&1);P=C+31264|0;R=z+4|0;E=z+8|0;F=b+4340|0;O=C+31260|0;N=0;do{J=N<<1;H=($(N,Q)|0)+f|0;I=0;do{L=I+J|0;U=(a[B+L>>0]|0)==0;if(U)c[P>>2]=sb(b)|0;else c[O>>2]=rb(b)|0;V=($(I,Q)|0)+e|0;T=c[A>>2]|0;X=c[m>>2]|0;S=c[X+13084>>2]|0;M=V>>S;K=H>>S;G=c[X+13156>>2]|0;S=Q>>S;X=c[X+13080>>2]|0;W=(1<>0]|0)==0?(W&H|0)==0:0)W=1;else{W=($(K+ -1|0,G)|0)+M|0;W=d[(c[F>>2]|0)+W>>0]|0}if((a[T+308>>0]|0)==0&(V|0)==0)V=1;else{V=M+ -1+($(K,G)|0)|0;V=d[(c[F>>2]|0)+V>>0]|0}X=(H>>X<>>0<2){c[z>>2]=0;c[R>>2]=1;c[E>>2]=26;V=0;X=1;W=26;break}else{c[z>>2]=V;X=(V+29&31)+2|0;c[R>>2]=X;W=(V+31&31)+2|0;c[E>>2]=W;break}else{c[z>>2]=V;c[R>>2]=X;if(!((V|0)==0|(X|0)==0)){c[E>>2]=0;W=0;break}if((V|0)==1|(X|0)==1){c[E>>2]=26;W=26;break}else{c[E>>2]=1;W=1;break}}while(0);if(U){if((V|0)>(X|0)){c[R>>2]=V;U=X&255;c[z>>2]=U}else{U=V;V=X}if((U|0)>(W|0)){c[E>>2]=U;X=W&255;c[z>>2]=X;W=U;U=X}if((V|0)>(W|0)){c[E>>2]=V;X=W&255;c[R>>2]=X}else{X=V;V=W}T=c[T+31264>>2]|0;T=((T|0)>=(U|0)&1)+T|0;T=((T|0)>=(X|0)&1)+T|0;T=((T|0)>=(V|0)&1)+T|0}else T=c[z+(c[T+31260>>2]<<2)>>2]|0;S=(S|0)==0?1:S;T=T&255;if((S|0)>0){U=0;do{X=($(U+K|0,G)|0)+M|0;ae((c[F>>2]|0)+X|0,T|0,S|0)|0;U=U+1|0}while((U|0)<(S|0))}a[C+L+31268>>0]=T;I=I+1|0}while((I|0)<(D|0));N=N+1|0}while((N|0)<(D|0));z=c[(c[m>>2]|0)+4>>2]|0;if((z|0)==3){B=0;do{z=B<<1;E=0;do{G=tb(b)|0;F=E+z|0;a[C+F+31281>>0]=G;A=a[C+F+31268>>0]|0;do if((G|0)!=4){G=a[1528+G>>0]|0;F=C+F+31277|0;if(A<<24>>24==G<<24>>24){a[F>>0]=34;break}else{a[F>>0]=G;break}}else a[C+F+31277>>0]=A;while(0);E=E+1|0}while((E|0)<(D|0));B=B+1|0}while((B|0)<(D|0))}else if(!z)break;else if((z|0)!=2){A=tb(b)|0;z=a[C+31268>>0]|0;if((A|0)==4){a[C+31277>>0]=z;break}A=a[1528+A>>0]|0;B=C+31277|0;if(z<<24>>24==A<<24>>24){a[B>>0]=34;break}else{a[B>>0]=A;break}}else{z=tb(b)|0;a[C+31281>>0]=z;A=a[C+31268>>0]|0;if((z|0)==4)z=A&255;else{z=a[1528+z>>0]|0;z=A<<24>>24==z<<24>>24?34:z&255}a[C+31277>>0]=a[1536+z>>0]|0;break}}else{G=c[m>>2]|0;B=c[G+13084>>2]|0;E=l>>B;C=c[G+13156>>2]|0;D=e>>B;B=f>>B;E=(E|0)==0?1:E;if((E|0)>0){F=b+4340|0;G=0;do{X=($(G+B|0,C)|0)+D|0;ae((c[F>>2]|0)+X|0,1,E|0)|0;G=G+1|0}while((G|0)<(E|0));G=c[m>>2]|0}K=c[A>>2]|0;V=c[b+160>>2]|0;A=c[V+32>>2]|0;D=$(A,f)|0;H=c[G+56>>2]|0;D=(c[V>>2]|0)+((e<>2]|0;J=c[G+13184>>2]|0;B=$(f>>J,E)|0;I=c[G+13172>>2]|0;B=(c[V+4>>2]|0)+((e>>I<>2]|0;X=c[G+13188>>2]|0;F=$(f>>X,C)|0;W=c[G+13176>>2]|0;F=(c[V+8>>2]|0)+((e>>W<>0]|0,l<>W,l>>X)|0)+($(l>>I,l>>J)|0)|0;G=($(d[G+13045>>0]|0,J)|0)+H|0;H=K+224|0;J=G+7>>3;I=c[K+240>>2]|0;X=c[H>>2]|0;I=(X&1|0)==0?I:I+ -1|0;I=(X&511|0)==0?I:I+ -1|0;K=(c[K+244>>2]|0)-I|0;if((K|0)<(J|0))I=0;else _c(H,I+J|0,K-J|0);if(!(a[b+2061>>0]|0))Cb(b,e,f,g);X=G>>>0>2147483639|(I|0)==0;W=X?0:G;V=X?0:I;c[z>>2]=V;c[z+12>>2]=W;c[z+16>>2]=W+8;c[z+4>>2]=V+(W+7>>3);c[z+8>>2]=0;if(X)z=-1094995529;else{W=b+2608|0;Ja[c[W>>2]&3](D,A,l,l,z,d[(c[m>>2]|0)+13044>>0]|0);X=c[m>>2]|0;Ja[c[W>>2]&3](B,E,l>>c[X+13172>>2],l>>c[X+13184>>2],z,d[X+13045>>0]|0);X=c[m>>2]|0;Ja[c[W>>2]&3](F,C,l>>c[X+13176>>2],l>>c[X+13188>>2],z,d[X+13045>>0]|0);z=0}if(a[(c[m>>2]|0)+13056>>0]|0)Tb(b,e,f,g);if((z|0)<0){X=z;i=j;return X|0}}while(0);do if(!(a[y>>0]|0)){if(!(a[x>>0]|0)){if(a[b+2061>>0]|0)break;Cb(b,e,f,g);break}x=c[m>>2]|0;if((c[v>>2]|0)==1)v=(d[w>>0]|0)+(c[x+13092>>2]|0)|0;else v=c[x+13088>>2]|0;a[p+31255>>0]=v;v=Ub(b,e,f,e,f,e,f,g,g,0,0,1520,1520)|0;if((v|0)<0){X=v;i=j;return X|0}}while(0);if((a[(c[q>>2]|0)+22>>0]|0)!=0?(a[p+300>>0]|0)==0:0)Bb(b,e,f,g);if(u){q=b+4316|0;g=p+272|0;u=0;while(1){ae((c[q>>2]|0)+t|0,a[g>>0]|0,r|0)|0;u=u+1|0;if((u|0)==(r|0))break;else t=t+h|0}}if((s&k|0)==0?(s&l+f|0)==0:0)c[p+276>>2]=a[p+272>>0];q=c[m>>2]|0;X=c[q+13064>>2]|0;g=l>>X;r=e>>X;e=f>>X;if((g|0)>0?(n=b+4336|0,o=c[p+31232>>2]&255,X=($(c[q+13140>>2]|0,e)|0)+r|0,ae((c[n>>2]|0)+X|0,o|0,g|0)|0,(g|0)!=1):0){p=1;do{X=($(c[(c[m>>2]|0)+13140>>2]|0,p+e|0)|0)+r|0;ae((c[n>>2]|0)+X|0,o|0,g|0)|0;p=p+1|0}while((p|0)!=(g|0))}e=c[m>>2]|0;m=1<>2];if(((k|0)%(m|0)|0|0)!=0?(k|0)<(c[e+13120>>2]|0):0){X=1;i=j;return X|0}X=l+f|0;if(((X|0)%(m|0)|0|0)!=0?(X|0)<(c[e+13124>>2]|0):0){X=1;i=j;return X|0}X=(hb(b)|0)==0&1;i=j;return X|0}function Tb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;m=1<>2]|0;l=c[n+13084>>2]|0;f=c[n+13156>>2]|0;k=m+d|0;j=c[n+13120>>2]|0;m=m+e|0;n=c[n+13124>>2]|0;h=e>>l;e=((m|0)>(n|0)?n:m)>>l;if((h|0)>=(e|0)){i=g;return}d=d>>l;j=((k|0)>(j|0)?j:k)>>l;k=(d|0)<(j|0);b=b+4348|0;do{if(k){m=$(h,f)|0;l=d;do{a[(c[b>>2]|0)+(l+m)>>0]=2;l=l+1|0}while((l|0)!=(j|0))}h=h+1|0}while((h|0)!=(e|0));i=g;return}function Ub(e,f,g,h,j,k,l,m,n,o,p,q,r){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;var s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;s=i;i=i+16|0;w=s+8|0;t=s;z=e+136|0;v=c[z>>2]|0;K=c[q>>2]|0;c[w>>2]=K;M=c[q+4>>2]|0;A=w+4|0;c[A>>2]=M;y=c[r>>2]|0;c[t>>2]=y;J=c[r+4>>2]|0;x=t+4|0;c[x>>2]=J;q=a[v+31254>>0]|0;do if(q<<24>>24){if((o|0)==1){c[v+288>>2]=d[v+p+31268>>0];if((c[(c[e+200>>2]|0)+4>>2]|0)==3){c[v+292>>2]=d[v+p+31277>>0];c[v+296>>2]=d[v+p+31281>>0];break}else{c[v+292>>2]=d[v+31277>>0];c[v+296>>2]=d[v+31281>>0];break}}}else{c[v+288>>2]=d[v+31268>>0];c[v+292>>2]=d[v+31277>>0];c[v+296>>2]=d[v+31281>>0]}while(0);r=e+200|0;G=c[r>>2]|0;B=(c[G+13076>>2]|0)>>>0>>0;if(((!B?(c[G+13072>>2]|0)>>>0>>0:0)?(d[v+31255>>0]|0)>(o|0):0)?!(q<<24>>24!=0&(o|0)==0):0)q=(ub(e,n)|0)&255;else{if((c[G+13088>>2]|0)==0?(c[v+31244>>2]|0)==0:0)G=(o|0)==0&(c[v+31248>>2]|0)!=0;else G=0;if(B)q=1;else q=(q<<24>>24!=0&(o|0)==0|G)&1}B=(n|0)>2;G=c[(c[r>>2]|0)+4>>2]|0;if(B)if(!G)L=y;else E=20;else if((G|0)==3)E=20;else L=y;do if((E|0)==20){G=(o|0)==0;if(!((K|0)==0&(G^1))){K=vb(e,o)|0;c[w>>2]=K;if((c[(c[r>>2]|0)+4>>2]|0)==2?q<<24>>24==0|(n|0)==3:0){M=vb(e,o)|0;c[A>>2]=M}if(!G)E=25}else{K=0;E=25}if((E|0)==25)if(!y){L=0;break}L=vb(e,o)|0;c[t>>2]=L;if((c[(c[r>>2]|0)+4>>2]|0)==2?q<<24>>24==0|(n|0)==3:0){J=vb(e,o)|0;c[x>>2]=J}}while(0);if(!(q<<24>>24)){A=c[r>>2]|0;y=c[A+13072>>2]|0;x=1<>2]|0;if(((o|0)==0?(c[v+31244>>2]|0)!=1:0)&(K|0)==0&(L|0)==0)if((c[A+4>>2]|0)==2?(M|J|0)!=0:0)E=37;else o=1;else E=37;if((E|0)==37){o=wb(e,o)|0;A=c[r>>2]|0}G=c[z>>2]|0;A=n-(c[A+13172>>2]|0)|0;z=G+31244|0;if((c[z>>2]|0)==1){I=1<>2]|0;L=c[K+4>>2]|0;if((L|0)==2){if(M){E=46;break}if(J){M=0;E=46;break}}if(!((c[z>>2]|0)!=1|(L|0)==0)){if(B|(L|0)==3){t=1<<(c[K+13172>>2]|0)+A;w=1<<(c[K+13184>>2]|0)+A;Ec(e,f,g,t,w);Wb(e,f,g,A,1);Wb(e,f,g,A,2);if((c[(c[r>>2]|0)+4>>2]|0)!=2)break;M=(1<>2]|0)+n,Ec(e,h,j,F,H),Wb(e,h,j,n,1),Wb(e,h,j,n,2),(c[(c[r>>2]|0)+4>>2]|0)==2):0){M=(1<>2]|0)+4>>2]|0)==2){F=(M|J|0)==0;E=48}else{F=1;E=48}a:do if((E|0)==48){E=e+204|0;do if((a[(c[E>>2]|0)+22>>0]|0)!=0?(D=G+300|0,(a[D>>0]|0)==0):0){M=jb(e)|0;J=G+280|0;c[J>>2]=M;if(M){M=(kb(e)|0)==1;H=c[J>>2]|0;if(M){H=0-H|0;c[J>>2]=H}}else H=0;a[D>>0]=1;M=(c[(c[r>>2]|0)+13192>>2]|0)/2|0;if((H|0)<(-26-M|0)|(H|0)>(M+25|0)){M=-1094995529;i=s;return M|0}else{Bb(e,k,l,m);break}}while(0);if((!((a[e+2080>>0]|0)==0|F)?(a[G+31256>>0]|0)==0:0)?(C=G+301|0,(a[C>>0]|0)==0):0){if(!(lb(e)|0)){a[G+302>>0]=0;a[G+303>>0]=0}else{l=c[E>>2]|0;if(!(a[l+1633>>0]|0))m=0;else{m=mb(e)|0;l=c[E>>2]|0}a[G+302>>0]=a[l+m+1634>>0]|0;a[G+303>>0]=a[(c[E>>2]|0)+m+1639>>0]|0}a[C>>0]=1}if((c[z>>2]|0)==1&(n|0)<4){m=c[G+288>>2]|0;if((m+ -6|0)>>>0<9)k=2;else k=(m+ -22|0)>>>0<9&1;m=c[G+292>>2]|0;if((m+ -6|0)>>>0<9)m=2;else m=(m+ -22|0)>>>0<9&1}else{k=0;m=0}l=G+304|0;a[l>>0]=0;if(I)zb(e,f,g,n,k,0);k=c[r>>2]|0;C=c[k+4>>2]|0;if(C){if(!(B|(C|0)==3)){if((p|0)!=3)break;p=1<>2]|0)+n;l=0;do{if((c[z>>2]|0)==1){M=(l<>2]|0)zb(e,h,(l<>2]|0)+4>>2]|0)==2?2:1)|0));w=0;while(1){if((c[z>>2]|0)==1){M=(w<>2]|0)zb(e,h,(w<=(((c[(c[r>>2]|0)+4>>2]|0)==2?2:1)|0))break a}}h=1<<(c[k+13172>>2]|0)+A;j=1<<(c[k+13184>>2]|0)+A;do if((a[(c[E>>2]|0)+1630>>0]|0)==0|I^1)a[l>>0]=0;else{if(c[z>>2]|0){M=(c[G+296>>2]|0)==4;a[l>>0]=M&1;if(!M)break}else a[l>>0]=1;Vb(e,0)}while(0);p=e+160|0;E=G+320|0;D=G+11680|0;C=1<0;B=e+(A+ -2<<2)+2612|0;F=G+284|0;I=0;do{if((c[z>>2]|0)==1){M=(I<>2]|0)){if(!(a[l>>0]|0))break;L=c[p>>2]|0;G=c[L+36>>2]|0;H=c[r>>2]|0;M=$(g>>c[H+13184>>2],G)|0;H=(c[L+4>>2]|0)+(M+(f>>c[H+13172>>2]<>2]))|0;if(k){I=0;do{b[D+(I<<1)>>1]=($(b[E+(I<<1)>>1]|0,c[F>>2]|0)|0)>>>3;I=I+1|0}while((I|0)!=(C|0));I=C}else I=0;Ga[c[B>>2]&7](H,D,G)}else zb(e,f,(I<>2]|0)+4>>2]|0)==2?2:1)|0));if(!(a[l>>0]|0))H=0;else{Vb(e,1);H=0}do{if((c[z>>2]|0)==1){M=(H<>2]|0)){if(!(a[l>>0]|0))break;L=c[p>>2]|0;w=c[L+40>>2]|0;G=c[r>>2]|0;M=$(g>>c[G+13188>>2],w)|0;G=(c[L+8>>2]|0)+(M+(f>>c[G+13176>>2]<>2]))|0;if(k){H=0;do{b[D+(H<<1)>>1]=($(b[E+(H<<1)>>1]|0,c[F>>2]|0)|0)>>>3;H=H+1|0}while((H|0)!=(C|0));H=C}else H=0;Ga[c[B>>2]&7](G,D,w)}else zb(e,f,(H<>2]|0)+4>>2]|0)==2?2:1)|0))}}while(0);if((o|0)!=0?(u=1<0):0){t=e+4344|0;r=0;do{w=$(r+g>>y,q)|0;h=0;do{a[(c[t>>2]|0)+((h+f>>y)+w)>>0]=1;h=h+x|0}while((h|0)<(u|0));r=r+x|0}while((r|0)<(u|0))}if(((a[e+2061>>0]|0)==0?(Cb(e,f,g,n),(a[(c[e+204>>2]|0)+40>>0]|0)!=0):0)?(a[v+31256>>0]|0)!=0:0)Tb(e,f,g,n)}else{v=n+ -1|0;u=1<>2]|0;f=xb(a,b)|0;if(!f){c[e+284>>2]=0;i=d;return}else{c[e+284>>2]=1-((yb(a,b)|0)<<1)<>2]|0;q=c[b+200>>2]|0;O=c[q+(h<<2)+13168>>2]|0;N=c[q+(h<<2)+13180>>2]|0;k=1<>2]|0;ga=k<>2]|0;P=e>>V&T;R=f>>V&T;S=T+2|0;Q=($(R,S)|0)+P|0;U=c[b+204>>2]|0;aa=c[U+1684>>2]|0;Q=c[aa+(Q<<2)>>2]|0;l=c[b+160>>2]|0;b=c[l+(h<<2)+32>>2]|0;l=c[l+(h<<2)>>2]|0;m=($(b,f>>N)|0)+(e>>O)|0;n=l+m|0;o=(h|0)==0;p=c[(o?r+288|0:r+292|0)>>2]|0;u=t+1|0;y=w+1|0;x=z+1|0;s=v+1|0;if(!(c[r+31288>>2]|0))fa=0;else fa=(Q|0)>(c[aa+(P+ -1+($(T&R+(ga>>V),S)|0)<<2)>>2]|0);da=fa&1;_=c[r+31292>>2]|0;H=c[r+31300>>2]|0;Z=c[r+31296>>2]|0;if(!(c[r+31304>>2]|0))ba=0;else ba=(Q|0)>(c[aa+(($(S,R+ -1|0)|0)+(T&P+(ea>>V))<<2)>>2]|0);S=ba&1;V=(ga<<1)+f|0;R=q+13124|0;aa=c[R>>2]|0;P=ga+f|0;V=((V|0)>(aa|0)?aa:V)-P>>N;aa=(ea<<1)+e|0;T=q+13120|0;ja=c[T>>2]|0;Q=ea+e|0;aa=((aa|0)>(ja|0)?ja:aa)-Q>>O;U=U+20|0;if((a[U>>0]|0)==1){ca=c[q+13084>>2]|0;ha=ga>>ca;ea=ea>>ca;ia=(1<>2]|0)-(P>>ca)|0;fa=(ha|0)>(fa|0)?fa:ha;if((fa|0)>0){da=0;ja=0;do{da=da|1;ja=ja+2|0}while((ja|0)<(fa|0))}else da=0}if(!((_|0)!=1|ia)){fa=(c[q+13160>>2]|0)-(f>>ca)|0;fa=(ha|0)>(fa|0)?fa:ha;if((fa|0)>0){_=0;ha=0;do{_=_|1;ha=ha+2|0}while((ha|0)<(fa|0))}else _=0}fa=(ga|0)!=0;if(!((Z|0)!=1|fa)){ga=(c[q+13156>>2]|0)-(e>>ca)|0;ga=(ea|0)>(ga|0)?ga:ea;if((ga|0)>0){Z=0;ha=0;do{Z=Z|1;ha=ha+2|0}while((ha|0)<(ga|0))}else Z=0}if(!(fa|ba^1)){ca=(c[q+13156>>2]|0)-(Q>>ca)|0;ca=(ea|0)>(ca|0)?ca:ea;if((ca|0)>0){S=0;ba=0;do{S=S|1;ba=ba+2|0}while((ba|0)<(ca|0))}else S=0}ba=u+0|0;ca=ba+64|0;do{a[ba>>0]=128;ba=ba+1|0}while((ba|0)<(ca|0));ba=w+0|0;ca=ba+65|0;do{a[ba>>0]=128;ba=ba+1|0}while((ba|0)<(ca|0));ea=S}else ea=S;ba=(H|0)!=0;if(ba){ja=a[l+(m+~b)>>0]|0;a[t>>0]=ja;a[w>>0]=ja}ca=(Z|0)!=0;if(ca)ce(y|0,l+(m-b)|0,k|0)|0;S=(ea|0)!=0;if(S?(Y=k+1|0,ce(w+Y|0,l+(k-b+m)|0,k|0)|0,X=$(d[l+(k+ -1-b+m+aa)>>0]|0,16843009)|0,W=k-aa|0,(W|0)>0):0){Y=aa+Y|0;aa=0;do{ja=w+(Y+aa)|0;a[ja>>0]=X;a[ja+1>>0]=X>>8;a[ja+2>>0]=X>>16;a[ja+3>>0]=X>>24;aa=aa+4|0}while((aa|0)<(W|0))}W=(_|0)!=0;if(W&(k|0)>0){Y=m+ -1|0;X=0;do{ja=X;X=X+1|0;a[t+X>>0]=a[l+(Y+($(ja,b)|0))>>0]|0}while((X|0)!=(k|0))}X=(da|0)!=0;if(X){aa=V+k|0;fa=m+ -1|0;if((V|0)>0){Y=k;do{ja=Y;Y=Y+1|0;a[t+Y>>0]=a[l+(fa+($(ja,b)|0))>>0]|0}while((Y|0)<(aa|0))}Y=$(d[l+(fa+($(aa+ -1|0,b)|0))>>0]|0,16843009)|0;aa=k-V|0;if((aa|0)>0){V=k+1+V|0;fa=0;do{ja=t+(V+fa)|0;a[ja>>0]=Y;a[ja+1>>0]=Y>>8;a[ja+2>>0]=Y>>16;a[ja+3>>0]=Y>>24;fa=fa+4|0}while((fa|0)<(aa|0))}}do if((a[U>>0]|0)==1?(ja=da|_,L=(ja|0)==0,ja=ja|H,M=(ja|0)==0,(Z|ea|ja|0)!=0):0){U=k<<1;V=c[T>>2]|0;if(((U<>O;R=c[R>>2]|0;if(((U<=(R|0))U=R-f>>N;if(!S)if((Q|0)<(V|0))O=k;else O=V-e>>O;else O=T;if(!X)if((P|0)<(R|0))U=k;else U=R-f>>N;N=a[w>>0]|0;if(M)a[t>>0]=N;a[t>>0]=N;if(!L){L=0;while(1)if((L|0)<(U|0))L=L+4|0;else break}if(!W?(K=$(N&255,16843009)|0,(k|0)>0):0){L=0;do{ja=t+(L|1)|0;a[ja>>0]=K;a[ja+1>>0]=K>>8;a[ja+2>>0]=K>>16;a[ja+3>>0]=K>>24;L=L+4|0}while((L|0)<(k|0))}do if(!X){L=$(d[t+k>>0]|0,16843009)|0;if((k|0)<=0)break;K=k+1|0;M=0;do{ja=t+(K+M)|0;a[ja>>0]=L;a[ja+1>>0]=L>>8;a[ja+2>>0]=L>>16;a[ja+3>>0]=L>>24;M=M+4|0}while((M|0)<(k|0))}while(0);f=(f|0)==0;if((e|0)==0&(U|0)>0){e=0;do{ja=t+(e|1)|0;a[ja>>0]=0;a[ja+1>>0]=0;a[ja+2>>0]=0;a[ja+3>>0]=0;e=e+4|0}while((e|0)<(U|0))}a[w>>0]=a[t>>0]|0;if(f)break;else e=0;while(1)if((e|0)<(O|0))e=e+4|0;else break}while(0);a:do if(!X){if(W){f=$(d[t+k>>0]|0,16843009)|0;if((k|0)<=0){J=84;break}J=k+1|0;e=0;while(1){ja=t+(J+e)|0;a[ja>>0]=f;a[ja+1>>0]=f>>8;a[ja+2>>0]=f>>16;a[ja+3>>0]=f>>24;e=e+4|0;if((e|0)>=(k|0)){J=84;break a}}}if(ba){e=$(d[t>>0]|0,16843009)|0;J=k<<1;if((k|0)>0)I=0;else{J=87;break}while(1){ja=t+(I|1)|0;a[ja>>0]=e;a[ja+1>>0]=e>>8;a[ja+2>>0]=e>>16;a[ja+3>>0]=e>>24;I=I+4|0;if((I|0)>=(J|0)){J=87;break a}}}if(ca){I=a[y>>0]|0;a[t>>0]=I;I=$(I&255,16843009)|0;H=k<<1;if((k|0)>0)J=0;else{J=89;break}while(1){ja=t+(J|1)|0;a[ja>>0]=I;a[ja+1>>0]=I>>8;a[ja+2>>0]=I>>16;a[ja+3>>0]=I>>24;J=J+4|0;if((J|0)>=(H|0)){J=89;break a}}}if(!S){a[t>>0]=-128;J=k<<1;f=(k|0)>0;if(f)e=0;else{J=84;break}do{ja=w+(e|1)|0;a[ja>>0]=-2139062144;a[ja+1>>0]=-2139062144>>8;a[ja+2>>0]=-2139062144>>16;a[ja+3>>0]=-2139062144>>24;e=e+4|0}while((e|0)<(J|0));if(f)e=0;else{J=84;break}while(1){ja=t+(e|1)|0;a[ja>>0]=-2139062144;a[ja+1>>0]=-2139062144>>8;a[ja+2>>0]=-2139062144>>16;a[ja+3>>0]=-2139062144>>24;e=e+4|0;if((e|0)>=(J|0)){J=84;break a}}}H=w+(k+1)|0;e=a[H>>0]|0;I=$(e&255,16843009)|0;G=(k|0)>0;if(G)J=0;else{a[t>>0]=e;break}do{ja=w+(J|1)|0;a[ja>>0]=I;a[ja+1>>0]=I>>8;a[ja+2>>0]=I>>16;a[ja+3>>0]=I>>24;J=J+4|0}while((J|0)<(k|0));I=a[H>>0]|0;a[t>>0]=I;I=$(I&255,16843009)|0;H=k<<1;if(G){G=0;do{ja=t+(G|1)|0;a[ja>>0]=I;a[ja+1>>0]=I>>8;a[ja+2>>0]=I>>16;a[ja+3>>0]=I>>24;G=G+4|0}while((G|0)<(H|0));J=92}else J=92}else J=84;while(0);if((J|0)==84)if((_|0)==0?(I=$(d[t+(k+1)>>0]|0,16843009)|0,(k|0)>0):0){J=0;do{ja=t+(J|1)|0;a[ja>>0]=I;a[ja+1>>0]=I>>8;a[ja+2>>0]=I>>16;a[ja+3>>0]=I>>24;J=J+4|0}while((J|0)<(k|0));J=87}else J=87;if((J|0)==87)if(!H){a[t>>0]=a[u>>0]|0;J=89}else J=89;if((J|0)==89)if((Z|0)==0?(G=$(d[t>>0]|0,16843009)|0,(k|0)>0):0){H=0;do{ja=w+(H|1)|0;a[ja>>0]=G;a[ja+1>>0]=G>>8;a[ja+2>>0]=G>>16;a[ja+3>>0]=G>>24;H=H+4|0}while((H|0)<(k|0));J=92}else J=92;if(((J|0)==92?!S:0)?(F=$(d[w+k>>0]|0,16843009)|0,(k|0)>0):0){H=k+1|0;G=0;do{ja=w+(H+G)|0;a[ja>>0]=F;a[ja+1>>0]=F>>8;a[ja+2>>0]=F>>16;a[ja+3>>0]=F>>24;G=G+4|0}while((G|0)<(k|0))}F=a[t>>0]|0;a[w>>0]=F;b:do if(!(c[q+13112>>2]|0)){if(o){if((p|0)==1|(k|0)==4){s=y;break}}else if(((p|0)==1?1:(c[q+4>>2]|0)!=3)|(k|0)==4){s=y;break}ja=p+ -26|0;ja=(ja|0)>-1?ja:26-p|0;ia=p+ -10|0;ia=(ia|0)>-1?ia:10-p|0;if((((ja|0)>(ia|0)?ia:ja)|0)>(c[1576+(g+ -3<<2)>>2]|0)){if((o&(a[q+13061>>0]|0)!=0&(g|0)==5?(D=F&255,E=a[w+64>>0]|0,C=E&255,ja=C+D-(d[w+32>>0]<<1)|0,(((ja|0)>-1?ja:0-ja|0)|0)<8):0)?(A=t+64|0,B=a[A>>0]|0,ja=(B&255)+D-(d[t+32>>0]<<1)|0,(((ja|0)>-1?ja:0-ja|0)|0)<8):0){a[v>>0]=F;a[v+64>>0]=E;w=0;do{ja=w;w=w+1|0;a[v+w>>0]=(($(D,63-ja|0)|0)+32+($(C,w)|0)|0)>>>6}while((w|0)!=63);w=0;while(1){v=w+1|0;a[t+v>>0]=(($(F&255,63-w|0)|0)+32+($(B&255,v)|0)|0)>>>6;if((v|0)==63)break b;F=a[t>>0]|0;B=a[A>>0]|0;w=v}}A=k<<1;D=a[t+A>>0]|0;a[z+A>>0]=D;B=a[w+A>>0]|0;a[v+A>>0]=B;A=A+ -2|0;C=(A|0)>-1;if(C){E=A;while(1){ja=E+1|0;ia=D;D=a[t+ja>>0]|0;a[z+ja>>0]=((ia&255)+2+((D&255)<<1)+(d[t+E>>0]|0)|0)>>>2;if((E|0)<=0)break;else E=E+ -1|0}}ja=((d[u>>0]|0)+2+((F&255)<<1)+(d[y>>0]|0)|0)>>>2&255;a[z>>0]=ja;a[v>>0]=ja;if(C)while(1){ja=A+1|0;ia=B;B=a[w+ja>>0]|0;a[v+ja>>0]=((ia&255)+2+((B&255)<<1)+(d[w+A>>0]|0)|0)>>>2;if((A|0)<=0){u=x;break}else A=A+ -1|0}else u=x}else s=y}else s=y;while(0);if(!p){Xb(n,s,u,b,g);i=j;return}else if((p|0)==1){if((k|0)>0){p=k;h=0;do{p=(d[u+h>>0]|0)+p+(d[s+h>>0]|0)|0;h=h+1|0}while((h|0)!=(k|0));q=p>>g+1;r=$(q,16843009)|0;g=0;do{p=($(g,b)|0)+m|0;h=0;do{ja=l+(p+h)|0;a[ja>>0]=r;a[ja+1>>0]=r>>8;a[ja+2>>0]=r>>16;a[ja+3>>0]=r>>24;h=h+4|0}while((h|0)<(k|0));g=g+1|0}while((g|0)!=(k|0))}else q=k>>g+1;if(!(o&(k|0)<32)){i=j;return}a[n>>0]=((q<<1)+2+(d[u>>0]|0)+(d[s>>0]|0)|0)>>>2;if((k|0)<=1){i=j;return}n=(q*3|0)+2|0;o=1;do{a[l+(o+m)>>0]=((d[s+o>>0]|0)+n|0)>>>2;o=o+1|0}while((o|0)!=(k|0));o=1;do{a[l+(($(o,b)|0)+m)>>0]=((d[u+o>>0]|0)+n|0)>>>2;o=o+1|0}while((o|0)!=(k|0));i=j;return}else{if(!(c[q+13104>>2]|0))l=0;else l=(a[r+31256>>0]|0)!=0;Yb(n,s,u,b,h,p,k,l&1);i=j;return}}function Xb(b,c,e,f,g){b=b|0;c=c|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;m=i;j=1<>0]|0,l-r|0)|0;s=r;r=r+1|0;u=$(d[h>>0]|0,r)|0;t=$(d[c+s>>0]|0,p)|0;a[b+(s+q)>>0]=v+j+u+t+($(d[k>>0]|0,n)|0)>>g}while((r|0)!=(j|0))}while((n|0)!=(j|0));i=m;return}function Yb(c,e,f,g,h,j,k,l){c=c|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;m=i;i=i+112|0;o=m;n=a[1592+(j+ -2)>>0]|0;p=o+k|0;q=($(n,k)|0)>>5;if((j|0)>17){s=e+ -1|0;r=j+ -11|0;if(r>>>0<15&(q|0)<-1){if((k|0)>=0){s=0;do{u=e+(s+ -1)|0;u=d[u>>0]|d[u+1>>0]<<8|d[u+2>>0]<<16|d[u+3>>0]<<24;v=o+(s+k)|0;a[v>>0]=u;a[v+1>>0]=u>>8;a[v+2>>0]=u>>16;a[v+3>>0]=u>>24;s=s+4|0}while((s|0)<=(k|0))}if((q|0)<0){r=b[1632+(r<<1)>>1]|0;do{a[o+(q+k)>>0]=a[f+((($(r,q)|0)+128>>8)+ -1)>>0]|0;q=q+1|0}while((q|0)!=0)}}else p=s;o=(k|0)>0;if(o){q=0;do{u=q;q=q+1|0;s=$(q,n)|0;r=s>>5;s=s&31;if(!s){r=r+1|0;s=$(u,g)|0;t=0;do{u=p+(r+t)|0;u=d[u>>0]|d[u+1>>0]<<8|d[u+2>>0]<<16|d[u+3>>0]<<24;v=c+(t+s)|0;a[v>>0]=u;a[v+1>>0]=u>>8;a[v+2>>0]=u>>16;a[v+3>>0]=u>>24;t=t+4|0}while((t|0)<(k|0))}else{t=32-s|0;v=$(u,g)|0;u=0;do{w=u+r|0;x=$(d[p+(w+1)>>0]|0,t)|0;a[c+(u+v)>>0]=(x+16+($(d[p+(w+2)>>0]|0,s)|0)|0)>>>5;w=u|1;x=w+r|0;y=$(d[p+(x+1)>>0]|0,t)|0;a[c+(w+v)>>0]=(y+16+($(d[p+(x+2)>>0]|0,s)|0)|0)>>>5;w=u|2;x=w+r|0;y=$(d[p+(x+1)>>0]|0,t)|0;a[c+(w+v)>>0]=(y+16+($(d[p+(x+2)>>0]|0,s)|0)|0)>>>5;w=u|3;x=w+r|0;y=$(d[p+(x+1)>>0]|0,t)|0;a[c+(w+v)>>0]=(y+16+($(d[p+(x+2)>>0]|0,s)|0)|0)>>>5;u=u+4|0}while((u|0)<(k|0))}}while((q|0)!=(k|0))}if(!((j|0)==26&(h|0)==0&(k|0)<32&(l|0)==0&o)){i=m;return}j=f+ -1|0;n=0;do{h=((d[f+n>>0]|0)-(d[j>>0]|0)>>1)+(d[e>>0]|0)|0;if(h>>>0>255)h=0-h>>31;a[c+($(n,g)|0)>>0]=h;n=n+1|0}while((n|0)!=(k|0));i=m;return}s=f+ -1|0;r=j+ -11|0;if(r>>>0<15&(q|0)<-1){if((k|0)>=0){s=0;do{x=f+(s+ -1)|0;x=d[x>>0]|d[x+1>>0]<<8|d[x+2>>0]<<16|d[x+3>>0]<<24;y=o+(s+k)|0;a[y>>0]=x;a[y+1>>0]=x>>8;a[y+2>>0]=x>>16;a[y+3>>0]=x>>24;s=s+4|0}while((s|0)<=(k|0))}if((q|0)<0){r=b[1632+(r<<1)>>1]|0;do{a[o+(q+k)>>0]=a[e+((($(r,q)|0)+128>>8)+ -1)>>0]|0;q=q+1|0}while((q|0)!=0)}}else p=s;q=(k|0)>0;if(q){o=0;do{r=o;o=o+1|0;t=$(o,n)|0;u=t>>5;t=t&31;if(!t){s=u+1|0;t=0;do{a[c+(($(t,g)|0)+r)>>0]=a[p+(s+t)>>0]|0;t=t+1|0}while((t|0)!=(k|0))}else{s=32-t|0;v=0;do{y=v+u|0;x=$(d[p+(y+1)>>0]|0,s)|0;a[c+(($(v,g)|0)+r)>>0]=(x+16+($(d[p+(y+2)>>0]|0,t)|0)|0)>>>5;v=v+1|0}while((v|0)!=(k|0))}}while((o|0)!=(k|0))}if(!((j|0)==10&(h|0)==0&(k|0)<32&(l|0)==0&q)){i=m;return}g=e+ -1|0;n=0;do{j=((d[e+n>>0]|0)-(d[g>>0]|0)>>1)+(d[f>>0]|0)|0;if(j>>>0>255)j=0-j>>31;a[c+n>>0]=j;j=n|1;h=((d[e+j>>0]|0)-(d[g>>0]|0)>>1)+(d[f>>0]|0)|0;if(h>>>0>255)h=0-h>>31;a[c+j>>0]=h;j=n|2;h=((d[e+j>>0]|0)-(d[g>>0]|0)>>1)+(d[f>>0]|0)|0;if(h>>>0>255)h=0-h>>31;a[c+j>>0]=h;j=n|3;h=((d[e+j>>0]|0)-(d[g>>0]|0)>>1)+(d[f>>0]|0)|0;if(h>>>0>255)h=0-h>>31;a[c+j>>0]=h;n=n+4|0}while((n|0)<(k|0));i=m;return}function Zb(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0;g=i;h=c[e>>2]|0;if(!h){i=g;return}if(!(c[h+304>>2]|0)){i=g;return}h=e+46|0;f=(d[h>>0]|0)&(f^255)&255;a[h>>0]=f;if(f<<24>>24){i=g;return}Wc(c[b+4>>2]|0,e+4|0);c[e+24>>2]=0;i=g;return}function _b(a){a=a|0;var b=0;b=i;Zb(a,a+2524|0,6);i=b;return}function $b(a){a=a|0;var b=0;b=i;Zb(a,a+2524|0,-1);i=b;return}function ac(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;h=d+4364|0;if(((c[(c[d+2524>>2]|0)+304>>2]|0)!=0?(b[d+2568>>1]|0)==(b[h>>1]|0):0)?(c[d+2544>>2]|0)==(f|0):0){j=-1094995529;i=g;return j|0}j=d+2524|0;if(c[(c[j>>2]|0)+304>>2]|0){j=-12;i=g;return j|0}if((Vc(c[d+4>>2]|0,d+2528|0,1)|0)<0){j=-12;i=g;return j|0}k=d+200|0;m=c[k>>2]|0;c[d+2540>>2]=$(c[m+13132>>2]|0,c[m+13128>>2]|0)|0;m=d+4520|0;l=c[j>>2]|0;c[l+244>>2]=(c[m>>2]|0)==1&1;c[l+240>>2]=((c[m>>2]|0)+ -1|0)>>>0<2&1;c[e>>2]=l;c[d+2520>>2]=j;a[d+2570>>0]=(a[d+1450>>0]|0)==0?2:3;c[d+2544>>2]=f;b[d+2568>>1]=b[h>>1]|0;j=d+2552|0;f=(c[k>>2]|0)+20|0;c[j+0>>2]=c[f+0>>2];c[j+4>>2]=c[f+4>>2];c[j+8>>2]=c[f+8>>2];c[j+12>>2]=c[f+12>>2];j=0;i=g;return j|0}function bc(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;l=d+2046|0;k=d+2572|0;h=d+4366|0;n=(f|0)==0;m=d+4364|0;f=d+200|0;while(1){if((a[l>>0]|0)==1){p=d+2524|0;o=d+2570|0;if(((a[o>>0]&8)==0?(c[d+2544>>2]|0)!=(c[k>>2]|0):0)?(b[d+2568>>1]|0)==(b[h>>1]|0):0)Zb(d,p,1)}else o=d+2570|0;if(!(a[o>>0]&1))o=0;else o=(b[d+2568>>1]|0)==(b[h>>1]|0)&1;if(((n?(b[h>>1]|0)==(b[m>>1]|0):0)?(j=c[f>>2]|0,(j|0)!=0):0)?(o|0)<=(c[j+(((c[j+72>>2]|0)+ -1|0)*12|0)+80>>2]|0):0){d=0;h=21;break}if(o){h=15;break}o=b[h>>1]|0;if(o<<16>>16==(b[m>>1]|0)){d=0;h=21;break}b[h>>1]=(o&65535)+1&255}if((h|0)==15){h=d+2524|0;e=Bd(e,c[h>>2]|0)|0;if(!(a[d+2570>>0]&8))Zb(d,h,1);else Zb(d,h,9);p=(e|0)<0?e:1;i=g;return p|0}else if((h|0)==21){i=g;return d|0}return 0}function cc(){var b=0,c=0,d=0,e=0,f=0;b=i;if(!(a[1664]|0))c=0;else{i=b;return}do{d=0;do{f=($(d<<1|1,c)|0)&127;e=f>>>0>63;f=e?f+ -64|0:f;e=e?-1:1;if((f|0)>31){f=64-f|0;e=0-e|0}a[1664+(c<<5)+d>>0]=$(a[2688+f>>0]|0,e)|0;d=d+1|0}while((d|0)!=32);c=c+1|0}while((c|0)!=32);i=b;return}function dc(a,b){a=a|0;b=b|0;c[a>>2]=1;c[a+4>>2]=1;c[a+8>>2]=2;c[a+12>>2]=3;c[a+16>>2]=4;c[a+20>>2]=1;c[a+24>>2]=5;c[a+28>>2]=2;c[a+32>>2]=2;c[a+36>>2]=3;c[a+40>>2]=4;c[a+44>>2]=5;c[a+48>>2]=3;c[a+52>>2]=4;c[a+56>>2]=5;c[a+60>>2]=6;c[a+64>>2]=1;c[a+68>>2]=1;c[a+72>>2]=2;c[a+1676>>2]=2;c[a+1680>>2]=3;c[a+1684>>2]=1;c[a+1688>>2]=2;c[a+1692>>2]=2;c[a+1696>>2]=3;c[a+1700>>2]=1;c[a+1704>>2]=2;return}function ec(b,c,d,e,f,g){b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0;h=i;if((e|0)<=0){i=h;return}k=(d|0)>0;j=8-g|0;m=0;while(1){if(k){l=0;do{a[b+l>>0]=(ad(f,g)|0)<>1]|0)+(d[l>>0]|0)|0;if(m>>>0>255)m=0-m>>31;a[l>>0]=m;k=k+1|0;if((k|0)==4)break;else j=j+2|0}h=h+1|0;if((h|0)==4)break;else{e=e+8|0;c=c+f|0}}i=g;return}function gc(c,e,f){c=c|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;h=0;while(1){j=e;k=0;while(1){l=c+k|0;m=(b[j>>1]|0)+(d[l>>0]|0)|0;if(m>>>0>255)m=0-m>>31;a[l>>0]=m;k=k+1|0;if((k|0)==8)break;else j=j+2|0}h=h+1|0;if((h|0)==8)break;else{e=e+16|0;c=c+f|0}}i=g;return}function hc(c,e,f){c=c|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;h=0;while(1){j=e;k=0;while(1){l=c+k|0;m=(b[j>>1]|0)+(d[l>>0]|0)|0;if(m>>>0>255)m=0-m>>31;a[l>>0]=m;k=k+1|0;if((k|0)==16)break;else j=j+2|0}h=h+1|0;if((h|0)==16)break;else{e=e+32|0;c=c+f|0}}i=g;return}function ic(c,e,f){c=c|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;h=0;while(1){j=e;k=0;while(1){l=c+k|0;m=(b[j>>1]|0)+(d[l>>0]|0)|0;if(m>>>0>255)m=0-m>>31;a[l>>0]=m;k=k+1|0;if((k|0)==32)break;else j=j+2|0}h=h+1|0;if((h|0)==32)break;else{e=e+64|0;c=c+f|0}}i=g;return}function jc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;c=c<<16>>16;e=7-c|0;c=1<0){f=1<0)g=0;else{i=d;return}while(1){h=a;j=0;while(1){b[h>>1]=(b[h>>1]|0)+f>>e;j=j+1|0;if((j|0)==(c|0))break;else h=h+2|0}g=g+1|0;if((g|0)==(c|0))break;else a=a+(c<<1)|0}i=d;return}if((c|0)<=0){i=d;return}e=0-e|0;f=0;while(1){g=a;h=0;while(1){b[g>>1]=b[g>>1]<>16);if(d){d=c+ -1|0;if((d|0)<=0){i=f;return}g=(c|0)>0;h=0;do{if(g){j=0;do{k=a+(j+c<<1)|0;b[k>>1]=(e[k>>1]|0)+(e[a+(j<<1)>>1]|0);j=j+1|0}while((j|0)!=(c|0))}a=a+(c<<1)|0;h=h+1|0}while((h|0)!=(d|0));i=f;return}if((c|0)<=0){i=f;return}d=(c|0)>1;h=0;while(1){if(d){j=b[a>>1]|0;g=1;do{k=a+(g<<1)|0;j=(e[k>>1]|0)+(j&65535)&65535;b[k>>1]=j;g=g+1|0}while((g|0)!=(c|0))}h=h+1|0;if((h|0)==(c|0))break;else a=a+(c<<1)|0}i=f;return}function lc(a){a=a|0;var c=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;c=i;e=0;d=a;while(1){p=b[d>>1]|0;m=d+16|0;n=b[m>>1]|0;g=n+p|0;f=d+24|0;o=b[f>>1]|0;l=o+n|0;j=p-o|0;h=d+8|0;k=(b[h>>1]|0)*74|0;o=((p-n+o|0)*74|0)+64|0;n=o>>7;if((n+32768|0)>>>0>65535)n=o>>31^32767;b[m>>1]=n;m=(g*29|0)+64+(l*55|0)+k|0;n=m>>7;if((n+32768|0)>>>0>65535)n=m>>31^32767;b[d>>1]=n;l=($(l,-29)|0)+64+(j*55|0)+k|0;m=l>>7;if((m+32768|0)>>>0>65535)m=l>>31^32767;b[h>>1]=m;g=(g*55|0)+64+(j*29|0)-k|0;h=g>>7;if((h+32768|0)>>>0>65535)h=g>>31^32767;b[f>>1]=h;e=e+1|0;if((e|0)==4){d=0;break}else d=d+2|0}while(1){p=b[a>>1]|0;l=a+4|0;m=b[l>>1]|0;g=m+p|0;e=a+6|0;n=b[e>>1]|0;k=n+m|0;h=p-n|0;f=a+2|0;j=(b[f>>1]|0)*74|0;n=((p-m+n|0)*74|0)+2048|0;m=n>>12;if((m+32768|0)>>>0>65535)m=n>>31^32767;b[l>>1]=m;l=(g*29|0)+2048+(k*55|0)+j|0;m=l>>12;if((m+32768|0)>>>0>65535)m=l>>31^32767;b[a>>1]=m;k=($(k,-29)|0)+2048+(h*55|0)+j|0;l=k>>12;if((l+32768|0)>>>0>65535)l=k>>31^32767;b[f>>1]=l;f=(g*55|0)+2048+(h*29|0)-j|0;g=f>>12;if((g+32768|0)>>>0>65535)g=f>>31^32767;b[e>>1]=g;d=d+1|0;if((d|0)==4)break;else a=a+8|0}i=c;return}function mc(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;c=i;f=0;e=a;while(1){l=b[e>>1]<<6;j=e+16|0;k=b[j>>1]<<6;g=k+l|0;k=l-k|0;l=e+8|0;m=b[l>>1]|0;d=e+24|0;n=b[d>>1]|0;h=(n*36|0)+(m*83|0)|0;m=($(n,-83)|0)+(m*36|0)|0;n=g+64+h|0;o=n>>7;if((o+32768|0)>>>0>65535)o=n>>31^32767;b[e>>1]=o;o=k+64+m|0;n=o>>7;if((n+32768|0)>>>0>65535)n=o>>31^32767;b[l>>1]=n;l=k-m+64|0;k=l>>7;if((k+32768|0)>>>0>65535)k=l>>31^32767;b[j>>1]=k;h=g-h+64|0;g=h>>7;if((g+32768|0)>>>0>65535)g=h>>31^32767;b[d>>1]=g;f=f+1|0;if((f|0)==4){e=0;break}else e=e+2|0}while(1){k=b[a>>1]<<6;h=a+4|0;l=b[h>>1]<<6;g=l+k|0;l=k-l|0;k=a+2|0;j=b[k>>1]|0;d=a+6|0;m=b[d>>1]|0;f=(m*36|0)+(j*83|0)|0;j=($(m,-83)|0)+(j*36|0)|0;m=g+2048+f|0;n=m>>12;if((n+32768|0)>>>0>65535)n=m>>31^32767;b[a>>1]=n;m=l+2048+j|0;n=m>>12;if((n+32768|0)>>>0>65535)n=m>>31^32767;b[k>>1]=n;k=l-j+2048|0;j=k>>12;if((j+32768|0)>>>0>65535)j=k>>31^32767;b[h>>1]=j;f=g-f+2048|0;g=f>>12;if((g+32768|0)>>>0>65535)g=f>>31^32767;b[d>>1]=g;e=e+1|0;if((e|0)==4)break;else a=a+8|0}i=c;return}function nc(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;h=i;i=i+64|0;j=h+48|0;p=h+32|0;f=h+16|0;g=h;q=(e|0)>8;r=e+4|0;k=j+4|0;l=j+8|0;m=j+12|0;o=0;r=(r|0)>8?8:r;n=d;while(1){c[p+0>>2]=0;c[p+4>>2]=0;c[p+8>>2]=0;c[p+12>>2]=0;w=(r|0)>1;s=0;do{if(w){t=p+(s<<2)|0;v=c[t>>2]|0;u=1;do{v=($(b[n+(u<<3<<1)>>1]|0,a[1664+(u<<2<<5)+s>>0]|0)|0)+v|0;u=u+2|0}while((u|0)<(r|0));c[t>>2]=v}s=s+1|0}while((s|0)!=4);v=b[n>>1]<<6;u=b[n+64>>1]<<6;w=u+v|0;u=v-u|0;v=b[n+32>>1]|0;t=b[n+96>>1]|0;s=(t*36|0)+(v*83|0)|0;v=($(t,-83)|0)+(v*36|0)|0;t=s+w|0;c[j>>2]=t;c[k>>2]=v+u;c[l>>2]=u-v;c[m>>2]=w-s;s=0;while(1){u=c[p+(s<<2)>>2]|0;v=t+64+u|0;w=v>>7;if((w+32768|0)>>>0>65535)w=v>>31^32767;b[n+(s<<3<<1)>>1]=w;t=t-u+64|0;u=t>>7;if((u+32768|0)>>>0>65535)u=t>>31^32767;b[n+(7-s<<3<<1)>>1]=u;s=s+1|0;if((s|0)==4)break;t=c[j+(s<<2)>>2]|0}if((r|0)<8)r=(o&3|0)==0&(o|0)!=0?r+ -4|0:r;o=o+1|0;if((o|0)==8)break;else n=n+2|0}j=q?8:e;n=(j|0)>1;k=f+4|0;l=f+8|0;m=f+12|0;o=0;while(1){c[g+0>>2]=0;c[g+4>>2]=0;c[g+8>>2]=0;c[g+12>>2]=0;e=0;do{if(n){r=g+(e<<2)|0;p=c[r>>2]|0;q=1;do{p=($(b[d+(q<<1)>>1]|0,a[1664+(q<<2<<5)+e>>0]|0)|0)+p|0;q=q+2|0}while((q|0)<(j|0));c[r>>2]=p}e=e+1|0}while((e|0)!=4);v=b[d>>1]<<6;u=b[d+8>>1]<<6;w=u+v|0;u=v-u|0;v=b[d+4>>1]|0;p=b[d+12>>1]|0;e=(p*36|0)+(v*83|0)|0;v=($(p,-83)|0)+(v*36|0)|0;p=e+w|0;c[f>>2]=p;c[k>>2]=v+u;c[l>>2]=u-v;c[m>>2]=w-e;e=0;while(1){q=c[g+(e<<2)>>2]|0;r=p+2048+q|0;s=r>>12;if((s+32768|0)>>>0>65535)s=r>>31^32767;b[d+(e<<1)>>1]=s;p=p-q+2048|0;q=p>>12;if((q+32768|0)>>>0>65535)q=p>>31^32767;b[d+(7-e<<1)>>1]=q;e=e+1|0;if((e|0)==4)break;p=c[f+(e<<2)>>2]|0}o=o+1|0;if((o|0)==8)break;else d=d+16|0}i=h;return}function oc(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;j=i;i=i+192|0;t=j+160|0;u=j+128|0;m=j+112|0;l=j+96|0;g=j+64|0;h=j+32|0;f=j+16|0;k=j;s=(e|0)>16;v=e+4|0;n=m+4|0;o=m+8|0;p=m+12|0;r=0;v=(v|0)>16?16:v;q=d;while(1){c[u+0>>2]=0;c[u+4>>2]=0;c[u+8>>2]=0;c[u+12>>2]=0;c[u+16>>2]=0;c[u+20>>2]=0;c[u+24>>2]=0;c[u+28>>2]=0;A=(v|0)>1;z=0;do{if(A){y=u+(z<<2)|0;w=c[y>>2]|0;x=1;do{w=($(b[q+(x<<4<<1)>>1]|0,a[1664+(x<<1<<5)+z>>0]|0)|0)+w|0;x=x+2|0}while((x|0)<(v|0));c[y>>2]=w}z=z+1|0}while((z|0)!=8);c[l+0>>2]=0;c[l+4>>2]=0;c[l+8>>2]=0;c[l+12>>2]=0;z=0;do{x=l+(z<<2)|0;w=c[x>>2]|0;y=1;do{w=($(b[q+(y<<5<<1)>>1]|0,a[1664+(y<<2<<5)+z>>0]|0)|0)+w|0;y=y+2|0}while((y|0)<8);c[x>>2]=w;z=z+1|0}while((z|0)!=4);z=b[q>>1]<<6;y=b[q+256>>1]<<6;A=y+z|0;y=z-y|0;z=b[q+128>>1]|0;w=b[q+384>>1]|0;x=(w*36|0)+(z*83|0)|0;z=($(w,-83)|0)+(z*36|0)|0;w=x+A|0;c[m>>2]=w;c[n>>2]=z+y;c[o>>2]=y-z;c[p>>2]=A-x;x=0;while(1){A=c[l+(x<<2)>>2]|0;c[t+(x<<2)>>2]=A+w;c[t+(7-x<<2)>>2]=w-A;x=x+1|0;if((x|0)==4){w=0;break}w=c[m+(x<<2)>>2]|0}do{x=c[t+(w<<2)>>2]|0;y=c[u+(w<<2)>>2]|0;A=x+64+y|0;z=A>>7;if((z+32768|0)>>>0>65535)z=A>>31^32767;b[q+(w<<4<<1)>>1]=z;x=x-y+64|0;y=x>>7;if((y+32768|0)>>>0>65535)y=x>>31^32767;b[q+(15-w<<4<<1)>>1]=y;w=w+1|0}while((w|0)!=8);if((v|0)<16)v=(r&3|0)==0&(r|0)!=0?v+ -4|0:v;r=r+1|0;if((r|0)==16)break;else q=q+2|0}o=s?16:e;p=(o|0)>1;l=f+4|0;m=f+8|0;n=f+12|0;q=0;while(1){c[h+0>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;r=0;do{if(p){e=h+(r<<2)|0;t=c[e>>2]|0;s=1;do{t=($(b[d+(s<<1)>>1]|0,a[1664+(s<<1<<5)+r>>0]|0)|0)+t|0;s=s+2|0}while((s|0)<(o|0));c[e>>2]=t}r=r+1|0}while((r|0)!=8);c[k+0>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;t=0;do{r=k+(t<<2)|0;s=c[r>>2]|0;e=1;do{s=($(b[d+(e<<1<<1)>>1]|0,a[1664+(e<<2<<5)+t>>0]|0)|0)+s|0;e=e+2|0}while((e|0)<8);c[r>>2]=s;t=t+1|0}while((t|0)!=4);z=b[d>>1]<<6;y=b[d+16>>1]<<6;A=y+z|0;y=z-y|0;z=b[d+8>>1]|0;r=b[d+24>>1]|0;e=(r*36|0)+(z*83|0)|0;z=($(r,-83)|0)+(z*36|0)|0;r=e+A|0;c[f>>2]=r;c[l>>2]=z+y;c[m>>2]=y-z;c[n>>2]=A-e;e=0;while(1){A=c[k+(e<<2)>>2]|0;c[g+(e<<2)>>2]=A+r;c[g+(7-e<<2)>>2]=r-A;e=e+1|0;if((e|0)==4){r=0;break}r=c[f+(e<<2)>>2]|0}do{e=c[g+(r<<2)>>2]|0;s=c[h+(r<<2)>>2]|0;u=e+2048+s|0;t=u>>12;if((t+32768|0)>>>0>65535)t=u>>31^32767;b[d+(r<<1)>>1]=t;e=e-s+2048|0;s=e>>12;if((s+32768|0)>>>0>65535)s=e>>31^32767;b[d+(15-r<<1)>>1]=s;r=r+1|0}while((r|0)!=8);q=q+1|0;if((q|0)==16)break;else d=d+32|0}i=j;return}function pc(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0;m=i;i=i+320|0;g=m+256|0;l=m+192|0;o=m+160|0;s=m+128|0;u=m+112|0;t=m+96|0;f=m+64|0;j=m+32|0;h=m+16|0;k=m;q=(e|0)>32;x=e+4|0;v=u+4|0;w=u+8|0;n=u+12|0;p=0;x=(x|0)>32?32:x;r=d;while(1){y=l+0|0;z=y+64|0;do{c[y>>2]=0;y=y+4|0}while((y|0)<(z|0));B=(x|0)>1;A=0;do{if(B){z=l+(A<<2)|0;y=c[z>>2]|0;C=1;do{y=($(b[r+(C<<5<<1)>>1]|0,a[1664+(C<<5)+A>>0]|0)|0)+y|0;C=C+2|0}while((C|0)<(x|0));c[z>>2]=y}A=A+1|0}while((A|0)!=16);c[s+0>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[s+16>>2]=0;c[s+20>>2]=0;c[s+24>>2]=0;c[s+28>>2]=0;y=(x|0)/2|0;z=(x|0)>3;A=0;do{if(z){D=s+(A<<2)|0;B=c[D>>2]|0;C=1;do{B=($(b[r+(C<<6<<1)>>1]|0,a[1664+(C<<1<<5)+A>>0]|0)|0)+B|0;C=C+2|0}while((C|0)<(y|0));c[D>>2]=B}A=A+1|0}while((A|0)!=8);c[t+0>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;A=0;do{B=t+(A<<2)|0;z=c[B>>2]|0;y=1;do{z=($(b[r+(y<<7<<1)>>1]|0,a[1664+(y<<2<<5)+A>>0]|0)|0)+z|0;y=y+2|0}while((y|0)<8);c[B>>2]=z;A=A+1|0}while((A|0)!=4);C=b[r>>1]<<6;B=b[r+1024>>1]<<6;D=B+C|0;B=C-B|0;C=b[r+512>>1]|0;y=b[r+1536>>1]|0;z=(y*36|0)+(C*83|0)|0;C=($(y,-83)|0)+(C*36|0)|0;y=z+D|0;c[u>>2]=y;c[v>>2]=C+B;c[w>>2]=B-C;c[n>>2]=D-z;z=0;while(1){D=c[t+(z<<2)>>2]|0;c[o+(z<<2)>>2]=D+y;c[o+(7-z<<2)>>2]=y-D;z=z+1|0;if((z|0)==4){y=0;break}y=c[u+(z<<2)>>2]|0}do{C=c[o+(y<<2)>>2]|0;D=c[s+(y<<2)>>2]|0;c[g+(y<<2)>>2]=D+C;c[g+(15-y<<2)>>2]=C-D;y=y+1|0}while((y|0)!=8);y=0;do{z=c[g+(y<<2)>>2]|0;A=c[l+(y<<2)>>2]|0;B=z+64+A|0;C=B>>7;if((C+32768|0)>>>0>65535)C=B>>31^32767;b[r+(y<<5<<1)>>1]=C;z=z-A+64|0;A=z>>7;if((A+32768|0)>>>0>65535)A=z>>31^32767;b[r+(31-y<<5<<1)>>1]=A;y=y+1|0}while((y|0)!=16);if((x|0)<32)x=(p&3|0)==0&(p|0)!=0?x+ -4|0:x;p=p+1|0;if((p|0)==32)break;else r=r+2|0}p=q?32:e;o=(p|0)>1;n=(p|0)/2|0;q=(p|0)>3;s=h+4|0;r=h+8|0;e=h+12|0;t=0;while(1){y=l+0|0;z=y+64|0;do{c[y>>2]=0;y=y+4|0}while((y|0)<(z|0));v=0;do{if(o){w=l+(v<<2)|0;u=c[w>>2]|0;x=1;do{u=($(b[d+(x<<1)>>1]|0,a[1664+(x<<5)+v>>0]|0)|0)+u|0;x=x+2|0}while((x|0)<(p|0));c[w>>2]=u}v=v+1|0}while((v|0)!=16);c[j+0>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;c[j+20>>2]=0;c[j+24>>2]=0;c[j+28>>2]=0;x=0;do{if(q){u=j+(x<<2)|0;w=c[u>>2]|0;v=1;do{D=v<<1;w=($(b[d+(D<<1)>>1]|0,a[1664+(D<<5)+x>>0]|0)|0)+w|0;v=v+2|0}while((v|0)<(n|0));c[u>>2]=w}x=x+1|0}while((x|0)!=8);c[k+0>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;u=0;do{v=k+(u<<2)|0;x=c[v>>2]|0;w=1;do{D=w<<2;x=($(b[d+(D<<1)>>1]|0,a[1664+(D<<5)+u>>0]|0)|0)+x|0;w=w+2|0}while((w|0)<8);c[v>>2]=x;u=u+1|0}while((u|0)!=4);C=b[d>>1]<<6;B=b[d+32>>1]<<6;D=B+C|0;B=C-B|0;C=b[d+16>>1]|0;u=b[d+48>>1]|0;v=(u*36|0)+(C*83|0)|0;C=($(u,-83)|0)+(C*36|0)|0;u=v+D|0;c[h>>2]=u;c[s>>2]=C+B;c[r>>2]=B-C;c[e>>2]=D-v;v=0;while(1){D=c[k+(v<<2)>>2]|0;c[f+(v<<2)>>2]=D+u;c[f+(7-v<<2)>>2]=u-D;v=v+1|0;if((v|0)==4){u=0;break}u=c[h+(v<<2)>>2]|0}do{C=c[f+(u<<2)>>2]|0;D=c[j+(u<<2)>>2]|0;c[g+(u<<2)>>2]=D+C;c[g+(15-u<<2)>>2]=C-D;u=u+1|0}while((u|0)!=8);u=0;do{v=c[g+(u<<2)>>2]|0;w=c[l+(u<<2)>>2]|0;x=v+2048+w|0;y=x>>12;if((y+32768|0)>>>0>65535)y=x>>31^32767;b[d+(u<<1)>>1]=y;v=v-w+2048|0;w=v>>12;if((w+32768|0)>>>0>65535)w=v>>31^32767;b[d+(31-u<<1)>>1]=w;u=u+1|0}while((u|0)!=16);t=t+1|0;if((t|0)==32)break;else d=d+64|0}i=m;return}function qc(a){a=a|0;var c=0,d=0,e=0,f=0;c=i;d=((((b[a>>1]|0)+1|0)>>>1)+32|0)>>>6&65535;e=0;do{f=e<<2;b[a+(f<<1)>>1]=d;b[a+((f|1)<<1)>>1]=d;b[a+((f|2)<<1)>>1]=d;b[a+((f|3)<<1)>>1]=d;e=e+1|0}while((e|0)!=4);i=c;return}function rc(a){a=a|0;var c=0,d=0,e=0,f=0;c=i;d=((((b[a>>1]|0)+1|0)>>>1)+32|0)>>>6&65535;e=0;do{f=e<<3;b[a+(f<<1)>>1]=d;b[a+((f|1)<<1)>>1]=d;b[a+((f|2)<<1)>>1]=d;b[a+((f|3)<<1)>>1]=d;b[a+((f|4)<<1)>>1]=d;b[a+((f|5)<<1)>>1]=d;b[a+((f|6)<<1)>>1]=d;b[a+((f|7)<<1)>>1]=d;e=e+1|0}while((e|0)!=8);i=c;return}function sc(a){a=a|0;var c=0,d=0,e=0,f=0,g=0;c=i;e=((((b[a>>1]|0)+1|0)>>>1)+32|0)>>>6&65535;d=0;do{f=d<<4;g=0;do{b[a+(g+f<<1)>>1]=e;g=g+1|0}while((g|0)!=16);d=d+1|0}while((d|0)!=16);i=c;return}function tc(a){a=a|0;var c=0,d=0,e=0,f=0,g=0;c=i;e=((((b[a>>1]|0)+1|0)>>>1)+32|0)>>>6&65535;d=0;do{f=d<<5;g=0;do{b[a+(g+f<<1)>>1]=e;g=g+1|0}while((g|0)!=32);d=d+1|0}while((d|0)!=32);i=c;return}function uc(e,f,g,h,j,k,l,m,n){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0;o=i;i=i+128|0;k=o;q=k+0|0;p=q+128|0;do{c[q>>2]=0;q=q+4|0}while((q|0)<(p|0));q=d[j+n+96>>0]|0;c[k+((q&31)<<2)>>2]=b[j+(n*10|0)+114>>1];c[k+((q+1&31)<<2)>>2]=b[j+(n*10|0)+116>>1];c[k+((q+2&31)<<2)>>2]=b[j+(n*10|0)+118>>1];c[k+((q+3&31)<<2)>>2]=b[j+(n*10|0)+120>>1];if((m|0)<=0){i=o;return}n=(l|0)>0;j=0;while(1){if(n){p=0;do{q=d[f+p>>0]|0;q=q+(c[k+(q>>>3<<2)>>2]|0)|0;if(q>>>0>255)q=0-q>>31;a[e+p>>0]=q;p=p+1|0}while((p|0)!=(l|0))}j=j+1|0;if((j|0)==(m|0))break;else{e=e+g|0;f=f+h|0}}i=o;return}function vc(e,f,g,h,j,k,l,m,n,o,p,q){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;var r=0,s=0,t=0,u=0;p=i;o=j+(n*10|0)+112|0;r=c[j+(n<<2)+100>>2]|0;if((r|0)!=1){if(c[k>>2]|0){q=b[o>>1]|0;if((m|0)>0){s=0;do{t=(d[f+($(s,h)|0)>>0]|0)+q|0;if(t>>>0>255)t=0-t>>31;a[e+($(s,g)|0)>>0]=t;s=s+1|0}while((s|0)!=(m|0));q=1}else q=1}else q=0;if(c[k+8>>2]|0){s=b[o>>1]|0;l=l+ -1|0;if((m|0)>0){t=0;do{u=(d[f+(($(t,h)|0)+l)>>0]|0)+s|0;if(u>>>0>255)u=0-u>>31;a[e+(($(t,g)|0)+l)>>0]=u;t=t+1|0}while((t|0)!=(m|0))}}if(!r){s=m;t=q;u=0;r=l;Dc(e,f,g,h,j,r,s,n,t,u);i=p;return}}else q=0;if(c[k+4>>2]|0){r=b[o>>1]|0;if((q|0)<(l|0)){s=q;do{t=(d[f+s>>0]|0)+r|0;if(t>>>0>255)t=0-t>>31;a[e+s>>0]=t;s=s+1|0}while((s|0)!=(l|0));r=1}else r=1}else r=0;if(!(c[k+12>>2]|0)){s=m;t=q;u=r;r=l;Dc(e,f,g,h,j,r,s,n,t,u);i=p;return}k=b[o>>1]|0;o=m+ -1|0;t=$(o,g)|0;m=$(o,h)|0;if((q|0)<(l|0))s=q;else{s=o;t=q;u=r;r=l;Dc(e,f,g,h,j,r,s,n,t,u);i=p;return}do{u=(d[f+(s+m)>>0]|0)+k|0;if(u>>>0>255)u=0-u>>31;a[e+(s+t)>>0]=u;s=s+1|0}while((s|0)!=(l|0));Dc(e,f,g,h,j,l,o,n,q,r);i=p;return}function wc(e,f,g,h,j,k,l,m,n,o,p,q){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;var r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=i;C=j+(n*10|0)+112|0;B=c[j+(n<<2)+100>>2]|0;A=(B|0)!=1;if(A){if(c[k>>2]|0){D=b[C>>1]|0;if((m|0)>0){E=0;do{G=(d[f+($(E,h)|0)>>0]|0)+D|0;if(G>>>0>255)G=0-G>>31;a[e+($(E,g)|0)>>0]=G;E=E+1|0}while((E|0)!=(m|0));D=1}else D=1}else D=0;if(c[k+8>>2]|0){E=b[C>>1]|0;l=l+ -1|0;if((m|0)>0){G=0;do{H=(d[f+(($(G,h)|0)+l)>>0]|0)+E|0;if(H>>>0>255)H=0-H>>31;a[e+(($(G,g)|0)+l)>>0]=H;G=G+1|0}while((G|0)!=(m|0))}}if(!B){C=1;E=0}else F=13}else{D=0;F=13}if((F|0)==13){if(c[k+4>>2]|0){F=b[C>>1]|0;if((D|0)<(l|0)){E=D;do{G=(d[f+E>>0]|0)+F|0;if(G>>>0>255)G=0-G>>31;a[e+E>>0]=G;E=E+1|0}while((E|0)!=(l|0));E=1}else E=1}else E=0;if(c[k+12>>2]|0){C=b[C>>1]|0;m=m+ -1|0;G=$(m,g)|0;H=$(m,h)|0;if((D|0)<(l|0)){F=D;do{I=(d[f+(F+H)>>0]|0)+C|0;if(I>>>0>255)I=0-I>>31;a[e+(F+G)>>0]=I;F=F+1|0}while((F|0)!=(l|0));C=0}else C=0}else C=0}Dc(e,f,g,h,j,l,m,n,D,E);j=(B|0)==2;if((a[q>>0]|0)==0&j?(c[k>>2]|0)==0:0)n=(c[k+4>>2]|0)==0;else n=0;H=n&1;n=q+1|0;B=(B|0)==3;if((a[n>>0]|0)==0&B?(c[k+4>>2]|0)==0:0)F=(c[k+8>>2]|0)==0;else F=0;J=F&1;F=q+2|0;if((a[F>>0]|0)==0&j?(c[k+8>>2]|0)==0:0)G=(c[k+12>>2]|0)==0;else G=0;I=G&1;G=q+3|0;if((a[G>>0]|0)==0&B?(c[k>>2]|0)==0:0)k=(c[k+12>>2]|0)==0;else k=0;k=k&1;A=A^1;if(!((a[o>>0]|0)==0|A)?(z=H+E|0,y=m-k|0,(z|0)<(y|0)):0)do{a[e+($(z,g)|0)>>0]=a[f+($(z,h)|0)>>0]|0;z=z+1|0}while((z|0)!=(y|0));if(!((a[o+1>>0]|0)==0|A)?(x=J+E|0,w=m-I|0,(x|0)<(w|0)):0){o=l+ -1|0;do{a[e+(o+($(x,g)|0))>>0]=a[f+(o+($(x,h)|0))>>0]|0;x=x+1|0}while((x|0)!=(w|0))}if(!((a[p>>0]|0)==0|C)?(v=H+D|0,u=l-J|0,(v|0)<(u|0)):0)do{a[e+v>>0]=a[f+v>>0]|0;v=v+1|0}while((v|0)!=(u|0));if(!((a[p+1>>0]|0)==0|C)?(t=k+D|0,r=l-I|0,(t|0)<(r|0)):0){u=m+ -1|0;p=$(u,h)|0;u=$(u,g)|0;do{a[e+(t+u)>>0]=a[f+(t+p)>>0]|0;t=t+1|0}while((t|0)!=(r|0))}if((a[q>>0]|0)!=0&j)a[e>>0]=a[f>>0]|0;if((a[n>>0]|0)!=0&B){J=l+ -1|0;a[e+J>>0]=a[f+J>>0]|0}if((a[F>>0]|0)!=0&j){J=m+ -1|0;I=l+ -1|0;a[e+(I+($(J,g)|0))>>0]=a[f+(I+($(J,h)|0))>>0]|0}if(!((a[G>>0]|0)!=0&B)){i=s;return}J=m+ -1|0;a[e+($(J,g)|0)>>0]=a[f+($(J,h)|0)>>0]|0;i=s;return}function xc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=i;Cc(a,b,1,c,d,e,f);i=g;return}function yc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=i;Cc(a,1,b,c,d,e,f);i=g;return}function zc(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=i;Bc(a,b,1,c,d,e);i=f;return}function Ac(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=i;Bc(a,1,b,c,d,e);i=f;return}function Bc(b,e,f,g,h,j){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;m=i;l=$(e,-2)|0;k=0-e|0;n=0;while(1){p=c[g+(n<<2)>>2]|0;if((p|0)>=1){s=0-p|0;r=(a[h+n>>0]|0)==0;q=(a[j+n>>0]|0)==0;o=0;t=b;while(1){v=t+k|0;x=d[v>>0]|0;u=d[t>>0]|0;w=(d[t+l>>0]|0)+4-(d[t+e>>0]|0)+(u-x<<2)>>3;if((w|0)<(s|0))w=s;else w=(w|0)>(p|0)?p:w;if(r){x=w+x|0;if(x>>>0>255)x=0-x>>31;a[v>>0]=x}if(q){u=u-w|0;if(u>>>0>255)u=0-u>>31;a[t>>0]=u}o=o+1|0;if((o|0)==4)break;else t=t+f|0}}n=n+1|0;if((n|0)==2)break;else b=b+(f<<2)|0}i=m;return}function Cc(b,e,f,g,h,j,k){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,aa=0,ba=0;t=i;o=$(e,-3)|0;p=$(e,-2)|0;q=0-e|0;r=e<<1;D=f*3|0;B=D+o|0;C=D+p|0;A=D-e|0;E=D+r|0;l=D+e|0;y=g>>3;v=g>>2;n=$(e,-4)|0;s=e*3|0;w=D+n|0;x=(f+e|0)*3|0;u=(g>>1)+g>>3;z=f<<2;m=f<<2;F=0;do{U=a[b+o>>0]|0;T=a[b+p>>0]|0;S=a[b+q>>0]|0;J=S&255;N=(U&255)-((T&255)<<1)+J|0;N=(N|0)>-1?N:0-N|0;P=a[b+r>>0]|0;Q=a[b+e>>0]|0;R=a[b>>0]|0;X=R&255;V=(P&255)-((Q&255)<<1)+X|0;V=(V|0)>-1?V:0-V|0;_=d[b+A>>0]|0;M=(d[b+B>>0]|0)-((d[b+C>>0]|0)<<1)+_|0;M=(M|0)>-1?M:0-M|0;Y=d[b+D>>0]|0;O=(d[b+E>>0]|0)-((d[b+l>>0]|0)<<1)+Y|0;O=(O|0)>-1?O:0-O|0;H=V+N|0;I=O+M|0;G=c[h+(F<<2)>>2]|0;W=a[j+F>>0]|0;L=a[k+F>>0]|0;do if((I+H|0)<(g|0)){Z=(G*5|0)+1>>1;aa=(d[b+n>>0]|0)-J|0;K=a[b+s>>0]|0;ba=(K&255)-X|0;if((((((((ba|0)>-1?ba:0-ba|0)+((aa|0)>-1?aa:0-aa|0)|0)<(y|0)?(ba=J-X|0,(((ba|0)>-1?ba:0-ba|0)|0)<(Z|0)):0)?(ba=(d[b+w>>0]|0)-_|0,aa=(d[b+x>>0]|0)-Y|0,(((aa|0)>-1?aa:0-aa|0)+((ba|0)>-1?ba:0-ba|0)|0)<(y|0)):0)?(ba=_-Y|0,(((ba|0)>-1?ba:0-ba|0)|0)<(Z|0)):0)?(H<<1|0)<(v|0):0)?(I<<1|0)<(v|0):0){G=G<<1;H=W<<24>>24==0;I=0-G|0;J=L<<24>>24==0;Y=K;K=1;L=b;while(1){V=L+o|0;U=U&255;W=L+p|0;T=T&255;X=L+q|0;N=S&255;R=R&255;S=L+e|0;Q=Q&255;M=L+r|0;O=P&255;P=Y&255;if(H){Y=d[L+n>>0]|0;Z=(U+4+Q+(N+T+R<<1)>>3)-N|0;if((Z|0)<(I|0))Z=I;else Z=(Z|0)>(G|0)?G:Z;a[X>>0]=Z+N;X=((U+2+T+N+R|0)>>>2)-T|0;if((X|0)<(I|0))X=I;else X=(X|0)>(G|0)?G:X;a[W>>0]=X+T;W=((U*3|0)+4+T+N+R+(Y<<1)>>3)-U|0;if((W|0)<(I|0))W=I;else W=(W|0)>(G|0)?G:W;a[V>>0]=W+U}if(J){T=(T+4+O+(R+N+Q<<1)>>3)-R|0;if((T|0)<(I|0))T=I;else T=(T|0)>(G|0)?G:T;a[L>>0]=T+R;T=((N+2+R+Q+O|0)>>>2)-Q|0;if((T|0)<(I|0))T=I;else T=(T|0)>(G|0)?G:T;a[S>>0]=T+Q;N=(N+4+R+Q+(O*3|0)+(P<<1)>>3)-O|0;if((N|0)<(I|0))N=I;else N=(N|0)>(G|0)?G:N;a[M>>0]=N+O}M=L+f|0;if((K|0)==4)break;U=a[L+(o+f)>>0]|0;T=a[L+(p+f)>>0]|0;S=a[L+(f-e)>>0]|0;R=a[M>>0]|0;Q=a[L+(f+e)>>0]|0;P=a[L+(r+f)>>0]|0;Y=a[L+(s+f)>>0]|0;K=K+1|0;L=M}b=b+m|0;break}H=G>>1;I=G*10|0;J=0-G|0;K=W<<24>>24!=0;L=L<<24>>24!=0;M=(M+N|0)<(u|0)&(K^1);N=0-H|0;O=(O+V|0)<(u|0)&(L^1);V=T;W=R;Y=Q;Q=1;R=b;while(1){X=U&255;T=R+p|0;V=V&255;_=R+q|0;Z=S&255;W=W&255;S=R+e|0;U=Y&255;P=P&255;Y=((W-Z|0)*9|0)+8+($(U-V|0,-3)|0)>>4;if((((Y|0)>-1?Y:0-Y|0)|0)<(I|0)){if((Y|0)<(J|0))Y=J;else Y=(Y|0)>(G|0)?G:Y;if(!K){aa=Y+Z|0;if(aa>>>0>255)aa=0-aa>>31;a[_>>0]=aa}if(!L){_=W-Y|0;if(_>>>0>255)_=0-_>>31;a[R>>0]=_}if(M){X=((X+1+Z|0)>>>1)-V+Y>>1;if((X|0)<(N|0))X=N;else X=(X|0)>(H|0)?H:X;V=X+V|0;if(V>>>0>255)V=0-V>>31;a[T>>0]=V}if(O){P=((W+1+P|0)>>>1)-U-Y>>1;if((P|0)<(N|0))P=N;else P=(P|0)>(H|0)?H:P;P=P+U|0;if(P>>>0>255)P=0-P>>31;a[S>>0]=P}}T=R+f|0;if((Q|0)==4)break;U=a[R+(o+f)>>0]|0;V=a[R+(p+f)>>0]|0;S=a[R+(f-e)>>0]|0;W=a[T>>0]|0;Y=a[R+(f+e)>>0]|0;P=a[R+(r+f)>>0]|0;Q=Q+1|0;R=T}b=b+m|0}else b=b+z|0;while(0);F=F+1|0}while((F|0)!=2);i=t;return}function Dc(e,f,g,h,j,k,l,m,n,o){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;var p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;t=i;v=c[j+(m<<2)+100>>2]|0;q=a[2728+(v<<2)>>0]|0;r=a[2730+(v<<2)>>0]|0;if((o|0)>=(l|0)){i=t;return}u=(n|0)<(k|0);s=o;p=$((a[2729+(v<<2)>>0]|0)+o|0,h)|0;v=$((a[2731+(v<<2)>>0]|0)+o|0,h)|0;w=$(o,g)|0;o=$(o,h)|0;while(1){if(u){y=p+q|0;x=v+r|0;z=n;do{A=a[f+(z+o)>>0]|0;B=a[f+(y+z)>>0]|0;if((A&255)>(B&255))B=3;else B=((A<<24>>24!=B<<24>>24)<<31>>31)+2|0;C=a[f+(x+z)>>0]|0;if((A&255)>(C&255))C=1;else C=(A<<24>>24!=C<<24>>24)<<31>>31;A=(b[j+(m*10|0)+(d[2720+(C+B)>>0]<<1)+112>>1]|0)+(A&255)|0;if(A>>>0>255)A=0-A>>31;a[e+(z+w)>>0]=A;z=z+1|0}while((z|0)!=(k|0))}s=s+1|0;if((s|0)==(l|0))break;else{p=p+h|0;v=v+h|0;w=w+g|0;o=o+h|0}}i=t;return}function Ec(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;j=i;k=c[b+136>>2]|0;l=(c[b+200>>2]|0)+13080|0;r=(1<>2])+ -1|0;o=r&e;n=r&f;q=(n|0)!=0|(a[k+309>>0]|0)!=0;m=q&1;c[k+31296>>2]=m;p=(o|0)!=0|(a[k+308>>0]|0)!=0;b=p&1;c[k+31292>>2]=b;if(!(r&(f|e)))p=d[k+311>>0]|0;else p=p&q&1;c[k+31300>>2]=p;if((o+g|0)==(1<>2]|0))m=(a[k+310>>0]|0)!=0&(n|0)==0&1;c[k+31308>>2]=m;if(!m){q=0;q=q&1;r=k+31304|0;c[r>>2]=q;r=h+f|0;q=k+316|0;q=c[q>>2]|0;q=(r|0)<(q|0);q=q?b:0;r=k+31288|0;c[r>>2]=q;i=j;return}q=(g+e|0)<(c[k+312>>2]|0);q=q&1;r=k+31304|0;c[r>>2]=q;r=h+f|0;q=k+316|0;q=c[q>>2]|0;q=(r|0)<(q|0);q=q?b:0;r=k+31288|0;c[r>>2]=q;i=j;return}function Fc(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;f=i;i=i+16|0;e=f;h=c[b+136>>2]|0;g=h+204|0;j=ud(13196)|0;c[e>>2]=j;if(!j){t=-12;i=f;return t|0}j=c[j+4>>2]|0;l=ud(468)|0;if(!l){t=-12;i=f;return t|0}k=c[l+4>>2]|0;c[k+4>>2]=1;n=k+8|0;c[n>>2]=1;a[k>>0]=0;c[k+348>>2]=1;p=k+352|0;m=k+380|0;q=k+408|0;o=0;do{c[p+(o<<2)>>2]=1;c[m+(o<<2)>>2]=0;c[q+(o<<2)>>2]=-1;o=o+1|0}while((o|0)<(c[n>>2]|0));c[k+436>>2]=0;c[k+440>>2]=1;a[k+444>>0]=0;o=b+208|0;wd(o);c[o>>2]=l;c[j>>2]=0;o=j+72|0;c[o>>2]=1;t=ad(g,8)|0;p=j+4|0;c[p>>2]=t;do if((t|0)<=3){a[j+8>>0]=0;n=j+13120|0;c[n>>2]=ed(g,32)|0;k=ed(g,32)|0;m=j+13124|0;c[m>>2]=k;k=Sc(c[n>>2]|0,k,0,c[b+4>>2]|0)|0;if((k|0)>=0){t=ad(g,8)|0;l=j+52|0;c[l>>2]=t+8;if(!t){p=c[p>>2]|0;if((p|0)==1){c[j+60>>2]=0;p=0}else if((p|0)==2){c[j+60>>2]=4;p=4}else if(!p){c[j+60>>2]=8;p=8}else{c[j+60>>2]=5;p=5}c[j+56>>2]=0;p=Cd(p)|0;if(p){c[j+13180>>2]=0;c[j+13168>>2]=0;t=d[p+5>>0]|0;c[j+13172>>2]=t;c[j+13176>>2]=t;t=d[p+6>>0]|0;c[j+13184>>2]=t;c[j+13188>>2]=t;c[j+64>>2]=8;if((c[o>>2]|0)>0){p=j+76|0;q=0;do{c[p+(q*12|0)>>2]=1;c[p+(q*12|0)+4>>2]=0;c[p+(q*12|0)+8>>2]=-1;q=q+1|0}while((q|0)<(c[o>>2]|0))}s=(fd(g)|0)+3|0;t=j+13064|0;c[t>>2]=s;s=1<>2]=r+(c[n>>2]|0)&s;c[m>>2]=r+(c[m>>2]|0)&s;s=j+13068|0;c[s>>2]=fd(g)|0;r=j+13072|0;c[r>>2]=(fd(g)|0)+2;o=fd(g)|0;p=c[r>>2]|0;q=j+13076|0;c[q>>2]=p+o;if(p>>>0<(c[t>>2]|0)>>>0){p=j+13088|0;c[p>>2]=0;o=j+13092|0;c[o>>2]=fd(g)|0;a[j+12941>>0]=dd(g)|0;u=dd(g)|0;c[j+68>>2]=u;if(u){u=j+13044|0;a[u>>0]=(ad(g,4)|0)+1;a[j+13045>>0]=(ad(g,4)|0)+1;v=(fd(g)|0)+3|0;c[j+13048>>2]=v;c[j+13052>>2]=v+(fd(g)|0);if((d[u>>0]|0|0)>(c[l>>2]|0)){k=-1094995529;break}a[j+13056>>0]=dd(g)|0}c[j+2184>>2]=0;a[j+12942>>0]=0;a[j+13060>>0]=0;a[j+13061>>0]=dd(g)|0;c[j+160>>2]=0;c[j+164>>2]=1;if((dd(g)|0)!=0?(v=dd(g)|0,cd(g,7),(v|0)!=0):0){c[j+13096>>2]=dd(g)|0;c[j+13100>>2]=dd(g)|0;c[j+13104>>2]=dd(g)|0;c[j+13108>>2]=dd(g)|0;dd(g)|0;c[j+13112>>2]=dd(g)|0;dd(g)|0;c[j+13116>>2]=dd(g)|0;dd(g)|0}g=c[n>>2]|0;c[j+12>>2]=g;n=c[m>>2]|0;c[j+16>>2]=n;t=c[t>>2]|0;v=(c[s>>2]|0)+t|0;c[j+13080>>2]=v;s=t+ -1|0;c[j+13084>>2]=s;m=1<>v;c[j+13128>>2]=u;m=n+ -1+m>>v;c[j+13132>>2]=m;c[j+13136>>2]=$(m,u)|0;c[j+13140>>2]=g>>t;c[j+13144>>2]=n>>t;u=c[r>>2]|0;c[j+13148>>2]=g>>u;c[j+13152>>2]=n>>u;c[j+13156>>2]=g>>s;c[j+13160>>2]=n>>s;u=v-u|0;c[j+13164>>2]=(1<>2]=((c[l>>2]|0)*6|0)+ -48;t=(1<>>0>6):0)?(c[p>>2]|0)>>>0<=u>>>0:0)?(c[o>>2]|0)>>>0<=u>>>0:0)?(c[q>>2]|0)>>>0<=(v>>>0>5?5:v)>>>0:0)?((c[h+216>>2]|0)-(c[h+212>>2]|0)|0)>=0:0){g=b+272|0;h=c[g>>2]|0;if((h|0)!=0?(v=c[e>>2]|0,(Vd(c[h+4>>2]|0,c[v+4>>2]|0,c[v+8>>2]|0)|0)==0):0){wd(e);v=0;i=f;return v|0}else h=0;do{j=b+(h<<2)+400|0;k=c[j>>2]|0;do if(k){if(c[c[k+4>>2]>>2]|0)break;wd(j)}while(0);h=h+1|0}while((h|0)!=256);h=c[g>>2]|0;do if(h){j=b+200|0;if((c[j>>2]|0)!=(c[h+4>>2]|0))break;u=b+1424|0;wd(u);v=vd(c[g>>2]|0)|0;c[u>>2]=v;if(v)break;c[j>>2]=0}while(0);wd(g);c[g>>2]=c[e>>2];v=0;i=f;return v|0}}else k=-1094995529}else k=-22}else k=-1094995529}}else k=-1094995529;while(0);wd(e);v=k;i=f;return v|0}function Gc(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0;f=i;i=i+16|0;e=f+4|0;j=f;l=b+136|0;g=c[l>>2]|0;n=g+204|0;h=nd(1692)|0;c[j>>2]=h;if(!h){I=-12;i=f;return I|0}I=rd(h,1692,6,0,0)|0;c[e>>2]=I;if(!I){kd(j);I=-12;i=f;return I|0}a[(c[j>>2]|0)+53>>0]=1;h=c[j>>2]|0;c[h+44>>2]=1;c[h+48>>2]=1;a[h+52>>0]=1;a[(c[j>>2]|0)+57>>0]=0;h=c[j>>2]|0;c[h+60>>2]=0;c[h+64>>2]=0;a[h+1629>>0]=2;h=fd(n)|0;a:do if((h>>>0<=255?(k=fd(n)|0,c[c[j>>2]>>2]=k,k>>>0<=31):0)?(m=c[b+(k<<2)+272>>2]|0,(m|0)!=0):0){k=c[m+4>>2]|0;I=(dd(n)|0)&255;a[(c[j>>2]|0)+41>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+39>>0]=I;I=ad(n,3)|0;c[(c[j>>2]|0)+1624>>2]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+4>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+5>>0]=I;I=(fd(n)|0)+1|0;c[(c[j>>2]|0)+8>>2]=I;I=(fd(n)|0)+1|0;c[(c[j>>2]|0)+12>>2]=I;I=gd(n)|0;c[(c[j>>2]|0)+16>>2]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+20>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+21>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+22>>0]=I;I=c[j>>2]|0;c[I+24>>2]=0;if(a[I+22>>0]|0){I=fd(n)|0;c[(c[j>>2]|0)+24>>2]=I}I=gd(n)|0;c[(c[j>>2]|0)+28>>2]=I;if((I+12|0)>>>0<=24?(I=gd(n)|0,c[(c[j>>2]|0)+32>>2]=I,(I+12|0)>>>0<=24):0){I=(dd(n)|0)&255;a[(c[j>>2]|0)+36>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+37>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+38>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+40>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+42>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+43>>0]=I;if(a[(c[j>>2]|0)+42>>0]|0){m=(fd(n)|0)+1|0;c[(c[j>>2]|0)+44>>2]=m;m=(fd(n)|0)+1|0;o=c[j>>2]|0;c[o+48>>2]=m;o=c[o+44>>2]|0;if(!o){b=-1094995529;break}if((m|0)==0?1:(o|0)>=(c[k+13120>>2]|0)){b=-1094995529;break}if((m|0)>=(c[k+13124>>2]|0)){b=-1094995529;break}m=pd(o,4)|0;c[(c[j>>2]|0)+1648>>2]=m;m=pd(c[(c[j>>2]|0)+48>>2]|0,4)|0;c[(c[j>>2]|0)+1652>>2]=m;m=c[j>>2]|0;if(!(c[m+1648>>2]|0)){b=-12;break}if(!(c[m+1652>>2]|0)){b=-12;break}p=(dd(n)|0)&255;a[(c[j>>2]|0)+52>>0]=p;p=c[j>>2]|0;if(!(a[p+52>>0]|0)){q=(c[p+44>>2]|0)+ -1|0;if((q|0)>0){o=0;m=0;r=0;do{q=(fd(n)|0)+1|0;p=c[j>>2]|0;c[(c[p+1648>>2]|0)+(r<<2)>>2]=q;o=_d(q|0,0,o|0,m|0)|0;m=D;r=r+1|0;q=(c[p+44>>2]|0)+ -1|0}while((r|0)<(q|0))}else{m=0;o=0}r=c[k+13128>>2]|0;s=((r|0)<0)<<31>>31;if(!(m>>>0>>0|(m|0)==(s|0)&o>>>0>>0)){b=-1094995529;break}I=Zd(r|0,s|0,o|0,m|0)|0;c[(c[p+1648>>2]|0)+(q<<2)>>2]=I;q=(c[p+48>>2]|0)+ -1|0;if((q|0)>0){p=0;o=0;r=0;do{q=(fd(n)|0)+1|0;m=c[j>>2]|0;c[(c[m+1652>>2]|0)+(r<<2)>>2]=q;p=_d(q|0,0,p|0,o|0)|0;o=D;r=r+1|0;q=(c[m+48>>2]|0)+ -1|0}while((r|0)<(q|0))}else{m=p;o=0;p=0}r=c[k+13132>>2]|0;s=((r|0)<0)<<31>>31;if(!(o>>>0>>0|(o|0)==(s|0)&p>>>0>>0)){b=-1094995529;break}I=Zd(r|0,s|0,p|0,o|0)|0;c[(c[m+1652>>2]|0)+(q<<2)>>2]=I}I=(dd(n)|0)&255;a[(c[j>>2]|0)+53>>0]=I}I=(dd(n)|0)&255;a[(c[j>>2]|0)+54>>0]=I;I=(dd(n)|0)&255;a[(c[j>>2]|0)+55>>0]=I;if((a[(c[j>>2]|0)+55>>0]|0)!=0?(I=(dd(n)|0)&255,a[(c[j>>2]|0)+56>>0]=I,I=(dd(n)|0)&255,a[(c[j>>2]|0)+57>>0]=I,(a[(c[j>>2]|0)+57>>0]|0)==0):0){m=(gd(n)|0)<<1;c[(c[j>>2]|0)+60>>2]=m;m=(gd(n)|0)<<1;I=c[j>>2]|0;c[I+64>>2]=m;if(((c[I+60>>2]|0)+13|0)>>>0>26){b=-1094995529;break}if((m+13|0)>>>0>26){b=-1094995529;break}}p=(dd(n)|0)&255;a[(c[j>>2]|0)+68>>0]=p;p=c[j>>2]|0;if(a[p+68>>0]|0){q=0;do{o=p+(q<<6)+69|0;m=o+16|0;do{a[o>>0]=16;o=o+1|0}while((o|0)<(m|0));a[p+q+1605>>0]=16;a[p+q+1611>>0]=16;q=q+1|0}while((q|0)!=6);o=p+453|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+517|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+581|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+645|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+709|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+773|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+837|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+901|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+965|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1029|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1093|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1157|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1221|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1285|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1349|0;q=2744;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1413|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1477|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));o=p+1541|0;q=2808;m=o+64|0;do{a[o>>0]=a[q>>0]|0;o=o+1|0;q=q+1|0}while((o|0)<(m|0));m=c[j>>2]|0;v=(c[l>>2]|0)+204|0;w=0;do{p=(w|0)>0?64:16;q=(w|0)>1;o=w+ -2|0;x=(w|0)==3?3:1;r=1<<(w<<1)+4;t=(r|0)>0;s=(w|0)==0;r=(r|0)<64?r:64;u=0;do{if(!(((dd(v)|0)&255)<<24>>24)){y=fd(v)|0;if(y){if(u>>>0>>0){b=-1094995529;break a}y=u-y|0;ce(m+(w*384|0)+(u<<6)+69|0,m+(w*384|0)+(y<<6)+69|0,p|0)|0;if(q)a[m+(o*6|0)+u+1605>>0]=a[m+(o*6|0)+y+1605>>0]|0}}else{if(q){z=(gd(v)|0)+8|0;a[m+(o*6|0)+u+1605>>0]=z}else z=8;if(t){y=0;do{if(s)A=(d[24+y>>0]<<2)+(d[8+y>>0]|0)|0;else A=(d[104+y>>0]<<3)+(d[40+y>>0]|0)|0;z=(z+256+(gd(v)|0)|0)%256|0;a[m+(w*384|0)+(u<<6)+A+69>>0]=z;y=y+1|0}while((y|0)!=(r|0))}}u=u+x|0}while((u|0)<6);w=w+1|0}while((w|0)<4);if((c[k+4>>2]|0)==3){o=0;do{a[m+o+1285>>0]=a[m+o+901>>0]|0;a[m+o+1349>>0]=a[m+o+965>>0]|0;a[m+o+1477>>0]=a[m+o+1093>>0]|0;a[m+o+1541>>0]=a[m+o+1157>>0]|0;o=o+1|0}while((o|0)!=64);a[m+1612>>0]=a[m+1606>>0]|0;a[m+1613>>0]=a[m+1607>>0]|0;a[m+1615>>0]=a[m+1609>>0]|0;a[m+1616>>0]=a[m+1610>>0]|0}}I=(dd(n)|0)&255;a[(c[j>>2]|0)+1617>>0]=I;I=(fd(n)|0)+2|0;c[(c[j>>2]|0)+1620>>2]=I;m=k+13080|0;if(I>>>0<=(c[m>>2]|0)>>>0){I=(dd(n)|0)&255;a[(c[j>>2]|0)+1628>>0]=I;do if((dd(n)|0)!=0?(I=dd(n)|0,ad(n,7)|0,(I|0)!=0):0){n=c[j>>2]|0;p=(c[l>>2]|0)+204|0;if(a[n+21>>0]|0)a[n+1629>>0]=(fd(p)|0)+2;a[n+1630>>0]=dd(p)|0;I=(dd(p)|0)&255;a[n+1631>>0]=I;if(I<<24>>24){a[n+1632>>0]=fd(p)|0;I=fd(p)|0;o=n+1633|0;a[o>>0]=I;if((I&255)>>>0<5)l=0;else break;while(1){a[n+l+1634>>0]=gd(p)|0;a[n+l+1639>>0]=gd(p)|0;if((l|0)<(d[o>>0]|0))l=l+1|0;else break}}a[n+1644>>0]=fd(p)|0;a[n+1645>>0]=fd(p)|0}while(0);l=pd((c[(c[j>>2]|0)+44>>2]|0)+1|0,4)|0;c[(c[j>>2]|0)+1656>>2]=l;l=pd((c[(c[j>>2]|0)+48>>2]|0)+1|0,4)|0;c[(c[j>>2]|0)+1660>>2]=l;l=k+13128|0;o=pd(c[l>>2]|0,4)|0;c[(c[j>>2]|0)+1664>>2]=o;o=c[j>>2]|0;n=c[o+1656>>2]|0;if(((n|0)!=0?(c[o+1660>>2]|0)!=0:0)?(c[o+1664>>2]|0)!=0:0){if(a[o+52>>0]|0){p=c[o+1648>>2]|0;if(!p){o=pd(c[o+44>>2]|0,4)|0;c[(c[j>>2]|0)+1648>>2]=o;o=pd(c[(c[j>>2]|0)+48>>2]|0,4)|0;c[(c[j>>2]|0)+1652>>2]=o;o=c[j>>2]|0;p=c[o+1648>>2]|0;if(!p){b=-12;break}}n=c[o+1652>>2]|0;if(!n){b=-12;break}q=o+44|0;s=c[q>>2]|0;if((s|0)>0){r=0;do{I=r;r=r+1|0;H=c[l>>2]|0;c[p+(I<<2)>>2]=(($(H,r)|0)/(s|0)|0)-(($(H,I)|0)/(s|0)|0);s=c[q>>2]|0}while((r|0)<(s|0))}q=o+48|0;s=c[q>>2]|0;if((s|0)>0){p=k+13132|0;r=0;do{I=r;r=r+1|0;H=c[p>>2]|0;c[n+(I<<2)>>2]=(($(H,r)|0)/(s|0)|0)-(($(H,I)|0)/(s|0)|0);s=c[q>>2]|0}while((r|0)<(s|0))}n=c[o+1656>>2]|0}c[n>>2]=0;q=o+44|0;if((c[q>>2]|0)>0){p=c[o+1648>>2]|0;r=0;s=0;do{r=(c[p+(s<<2)>>2]|0)+r|0;s=s+1|0;c[n+(s<<2)>>2]=r}while((s|0)<(c[q>>2]|0))}s=c[o+1660>>2]|0;c[s>>2]=0;r=o+48|0;if((c[r>>2]|0)>0){q=c[o+1652>>2]|0;t=0;p=0;do{t=(c[q+(p<<2)>>2]|0)+t|0;p=p+1|0;c[s+(p<<2)>>2]=t}while((p|0)<(c[r>>2]|0))}r=c[l>>2]|0;if((r|0)>0){o=c[o+1664>>2]|0;p=0;q=0;do{q=(p>>>0>(c[n+(q<<2)>>2]|0)>>>0&1)+q|0;c[o+(p<<2)>>2]=q;p=p+1|0;r=c[l>>2]|0}while((p|0)<(r|0))}x=$(c[k+13132>>2]|0,r)|0;n=pd(x,4)|0;c[(c[j>>2]|0)+1668>>2]=n;n=pd(x,4)|0;c[(c[j>>2]|0)+1672>>2]=n;n=pd(x,4)|0;c[(c[j>>2]|0)+1676>>2]=n;n=k+13164|0;q=(c[n>>2]|0)+2|0;q=pd($(q,q)|0,4)|0;c[(c[j>>2]|0)+1688>>2]=q;q=c[j>>2]|0;p=c[q+1668>>2]|0;if(!p){b=-12;break}w=c[q+1672>>2]|0;if(!w){b=-12;break}o=c[q+1676>>2]|0;if(!o){b=-12;break}if(!(c[q+1688>>2]|0)){b=-12;break}if((x|0)>0){B=q+44|0;r=q+48|0;s=c[q+1660>>2]|0;v=c[q+1648>>2]|0;u=c[q+1656>>2]|0;t=q+1652|0;A=0;do{C=c[l>>2]|0;y=(A|0)%(C|0)|0;z=(A|0)/(C|0)|0;G=c[B>>2]|0;E=0;while(1){if((E|0)>=(G|0)){E=0;break}F=E+1|0;if(y>>>0<(c[u+(F<<2)>>2]|0)>>>0)break;else E=F}H=c[r>>2]|0;F=0;while(1){if((F|0)>=(H|0)){F=0;break}G=F+1|0;if(z>>>0<(c[s+(G<<2)>>2]|0)>>>0)break;else F=G}if((E|0)>0){G=c[(c[t>>2]|0)+(F<<2)>>2]|0;H=0;I=0;do{I=($(c[v+(H<<2)>>2]|0,G)|0)+I|0;H=H+1|0}while((H|0)!=(E|0))}else I=0;if((F|0)>0){G=c[t>>2]|0;H=0;do{I=($(c[G+(H<<2)>>2]|0,C)|0)+I|0;H=H+1|0}while((H|0)!=(F|0))}H=$(c[v+(E<<2)>>2]|0,z-(c[s+(F<<2)>>2]|0)|0)|0;I=I+y+H-(c[u+(E<<2)>>2]|0)|0;c[p+(A<<2)>>2]=I;c[w+(I<<2)>>2]=A;A=A+1|0}while((A|0)!=(x|0))}else r=q+48|0;x=c[r>>2]|0;if((x|0)>0){s=q+44|0;t=q+1660|0;q=q+1656|0;z=c[s>>2]|0;u=0;w=0;while(1){v=u;u=u+1|0;if((z|0)>0){x=c[t>>2]|0;y=x+(u<<2)|0;G=c[y>>2]|0;B=z;z=0;do{E=c[x+(v<<2)>>2]|0;A=z;z=z+1|0;if(E>>>0>>0){B=c[q>>2]|0;C=B+(z<<2)|0;F=c[C>>2]|0;do{H=c[B+(A<<2)>>2]|0;if(H>>>0>>0){do{c[o+(c[p+(($(c[l>>2]|0,E)|0)+H<<2)>>2]<<2)>>2]=w;H=H+1|0;F=c[C>>2]|0}while(H>>>0>>0);G=c[y>>2]|0}E=E+1|0}while(E>>>0>>0);B=c[s>>2]|0}w=w+1|0}while((z|0)<(B|0));v=c[r>>2]|0;z=B}else v=x;if((u|0)>=(v|0))break;else x=v}}else w=0;o=pd(w,4)|0;c[(c[j>>2]|0)+1680>>2]=o;o=c[j>>2]|0;p=c[o+1680>>2]|0;if(!p){b=-12;break}r=o+48|0;u=c[r>>2]|0;if((u|0)>0){q=o+44|0;t=c[q>>2]|0;s=0;do{if((t|0)>0){u=c[o+1660>>2]|0;v=c[o+1656>>2]|0;w=0;do{I=$(c[l>>2]|0,c[u+(s<<2)>>2]|0)|0;c[p+(($(t,s)|0)+w<<2)>>2]=(c[v+(w<<2)>>2]|0)+I;w=w+1|0;t=c[q>>2]|0}while((w|0)<(t|0));u=c[r>>2]|0}s=s+1|0}while((s|0)<(u|0))}k=(c[m>>2]|0)-(c[k+13072>>2]|0)|0;v=c[n>>2]|0;c[o+1684>>2]=(c[o+1688>>2]|0)+(v+3<<2);p=v+2|0;if((p|0)>0){m=c[(c[j>>2]|0)+1688>>2]|0;o=0;do{c[m+(($(p,o)|0)<<2)>>2]=-1;c[m+(o<<2)>>2]=-1;o=o+1|0;v=c[n>>2]|0;p=v+2|0}while((o|0)<(p|0))}if((v|0)>-1){m=c[j>>2]|0;j=m+1668|0;p=k<<1;o=(k|0)>0;m=m+1684|0;q=0;while(1){if((v|0)>-1){r=q>>k;t=c[j>>2]|0;s=c[m>>2]|0;u=0;while(1){z=c[t+(($(c[l>>2]|0,r)|0)+(u>>k)<<2)>>2]<>2]=z;v=c[n>>2]|0;if((u|0)<(v|0))u=u+1|0;else break}}if((q|0)<(v|0))q=q+1|0;else break}}if(((c[g+216>>2]|0)-(c[g+212>>2]|0)|0)<0){b=0;break}I=b+(h<<2)+400|0;wd(I);c[I>>2]=c[e>>2];I=0;i=f;return I|0}else b=-12}else b=-1094995529}else b=-1094995529}else b=-1094995529;while(0);wd(e);I=b;i=f;return I|0}function Hc(a,b){a=a|0;b=b|0;var d=0;a=i;i=i+16|0;d=a;c[d>>2]=b;kd(b+1648|0);kd(b+1652|0);kd(b+1656|0);kd(b+1660|0);kd(b+1664|0);kd(b+1668|0);kd(b+1672|0);kd(b+1680|0);kd(b+1676|0);kd(b+1688|0);kd(d);i=a;return}function Ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;d=a+136|0;e=a+2512|0;while(1){f=(c[d>>2]|0)+204|0;g=0;do{h=ad(f,8)|0;g=h+g|0}while((h|0)==255);h=0;do{j=ad(f,8)|0;h=j+h|0}while((j|0)==255);do if((c[e>>2]|0)==39)if((g|0)==256){Jc(a);break}else{cd(f,h<<3);break}else if((g|0)==132){Jc(a);break}else{cd(f,h<<3);break}while(0);f=c[d>>2]|0;if(((c[f+216>>2]|0)-(c[f+212>>2]|0)|0)<=0){a=14;break}if((bd(f+204|0,8)|0)==128){a=14;break}}if((a|0)==14){i=b;return 1}return 0}function Jc(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;e=(c[b+136>>2]|0)+204|0;g=(ad(e,8)|0)&255;f=b+4468|0;h=0;do{if((g|0)==1)cd(e,16);else if(!g){a[f>>0]=1;j=0;do{a[b+(h<<4)+j+4420>>0]=ad(e,8)|0;j=j+1|0}while((j|0)!=16)}else if((g|0)==2)cd(e,32);h=h+1|0}while((h|0)!=3);i=d;return}function Kc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;d=i;f=c[b+52>>2]|0;e=a+60|0;if((f|0)>0){if((c[e>>2]|0)==0?(f=nd(f)|0,c[e>>2]=f,(f|0)==0):0){f=-12;i=d;return f|0}}else c[e>>2]=0;f=a+12|0;c[f>>2]=b;c[a+424>>2]=0;c[a+800>>2]=1;h=a+912|0;g=a+936|0;c[h+0>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[g>>2]=0;c[g+4>>2]=-2147483648;g=a+928|0;c[g>>2]=0;c[g+4>>2]=-2147483648;a=Fa[c[b+76>>2]&3](a)|0;if((a|0)>=0){h=0;i=d;return h|0}kd(e);c[f>>2]=0;h=a;i=d;return h|0}function Lc(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;if(!a){i=b;return 0}e=a+12|0;f=c[e>>2]|0;if((f|0)!=0?(d=c[f+92>>2]|0,(d|0)!=0):0)Fa[d&3](a)|0;c[a+796>>2]=0;kd(a+60|0);c[e>>2]=0;c[a+808>>2]=0;i=b;return 0}function Mc(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0;h=i;if((f|0)<=0){i=h;return 0}j=(e|0)==0;k=0;do{l=d+($(k,g)|0)|0;l=Ka[b&1](a,l)|0;if(!j)c[e+(k<<2)>>2]=l;k=k+1|0}while((k|0)!=(f|0));i=h;return 0}function Nc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0;g=i;if((f|0)<=0){i=g;return 0}h=(e|0)==0;j=0;do{k=Ia[b&1](a,d,j,0)|0;if(!h)c[e+(j<<2)>>2]=k;j=j+1|0}while((j|0)!=(f|0));i=g;return 0}function Oc(b,f,g){b=b|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;h=Cd(c[f+76>>2]|0)|0;b=h+4|0;if(!(a[b>>0]|0)){p=0;i=g;return p|0}k=f+64|0;l=h+5|0;m=f+68|0;n=h+6|0;j=0;while(1){p=($((((e[h+(j<<1)+8>>1]|0)>>>11&15)+8|0)>>>3,c[k>>2]|0)|0)+31&-32;if((j+ -1|0)>>>0<2){p=0-(0-p>>d[l>>0])|0;c[f+(j<<2)+32>>2]=p;o=0-(0-((c[m>>2]|0)+31&-32)>>d[n>>0])|0}else{c[f+(j<<2)+32>>2]=p;o=(c[m>>2]|0)+31&-32}o=td(($(p,o)|0)+32|0)|0;c[f+(j<<2)+304>>2]=o;if(!o){b=-1;f=8;break}c[f+(j<<2)>>2]=c[o+4>>2];j=j+1|0;if((j|0)>=(d[b>>0]|0)){b=0;f=8;break}}if((f|0)==8){i=g;return b|0}return 0}function Pc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;ae(a|0,0,976)|0;e=(b|0)!=0;if(e){c[a+8>>2]=c[b+8>>2];c[a+48>>2]=c[b+12>>2]}else c[a+8>>2]=-1;c[a+100>>2]=0;c[a+104>>2]=1;c[a+888>>2]=0;c[a+892>>2]=1;c[a+896>>2]=0;c[a+900>>2]=1;c[a+476>>2]=1;c[a+816>>2]=1;c[a+820>>2]=1;c[a+220>>2]=0;c[a+224>>2]=1;c[a+136>>2]=-1;c[a+416>>2]=-1;g=a+696|0;c[g>>2]=0;c[g+4>>2]=-2147483648;if((e?(f=c[b+52>>2]|0,(f|0)!=0):0)?(g=nd(f)|0,c[a+60>>2]=g,(g|0)==0):0){g=-12;i=d;return g|0}g=0;i=d;return g|0}function Qc(a){a=a|0;var b=0,c=0;b=i;c=hd(976)|0;if(c){if((Pc(c,a)|0)<0){jd(c);c=0}}else c=0;i=b;return c|0}function Rc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;i=i+80|0;g=f;k=g+0|0;j=e+0|0;h=k+80|0;do{c[k>>2]=c[j>>2];k=k+4|0;j=j+4|0}while((k|0)<(h|0));h=a+12|0;j=c[h>>2]|0;if(!j){k=-22;i=f;return k|0}if(c[j+8>>2]|0){k=-22;i=f;return k|0}c[d>>2]=0;j=c[a+124>>2]|0;k=c[a+128>>2]|0;if(!j){if(k){k=-22;i=f;return k|0}}else{if(!((j|0)>0&(k|0)>0)){k=-22;i=f;return k|0}if((j+128|0)>>>0>=(268435455/((k+128|0)>>>0)|0)>>>0){k=-22;i=f;return k|0}}zd(b);h=c[h>>2]|0;if(((c[h+16>>2]&32|0)==0?(c[e+28>>2]|0)==0:0)?(c[a+808>>2]&1|0)==0:0){k=0;i=f;return k|0}g=Ia[c[h+88>>2]&1](a,b,d,g)|0;if(!(c[d>>2]|0)){zd(b);k=g;i=f;return k|0}else{k=a+424|0;c[k>>2]=(c[k>>2]|0)+1;k=g;i=f;return k|0}return 0}function Sc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=i;if((a|0)>0&(b|0)>0?(a+128|0)>>>0<(268435455/((b+128|0)>>>0)|0)>>>0:0){d=0;i=c;return d|0}d=-22;i=c;return d|0}function Tc(a,b){a=a|0;b=b|0;return 0}function Uc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;e=a+8|0;if(!(c[e>>2]|0)){g=c[a+116>>2]|0;h=a+120|0;j=c[h>>2]|0;if(!((g|0)>0&(j|0)>0)){l=-22;i=f;return l|0}if((g+128|0)>>>0>=(268435455/((j+128|0)>>>0)|0)>>>0){l=-22;i=f;return l|0}j=c[a+136>>2]|0;if((j|0)<0){l=-22;i=f;return l|0}k=b+64|0;l=b+68|0;if((c[k>>2]|0)>=1?(c[l>>2]|0)>=1:0)g=1;else{m=a+792|0;n=0-(0-(c[a+124>>2]|0)>>c[m>>2])|0;c[k>>2]=(g|0)>(n|0)?g:n;k=c[h>>2]|0;g=0-(0-(c[a+128>>2]|0)>>c[m>>2])|0;c[l>>2]=(k|0)>(g|0)?k:g;g=0}c[b+76>>2]=j}else g=1;d=za[c[a+476>>2]&1](a,b,d)|0;if(c[e>>2]|g){n=d;i=f;return n|0}c[b+64>>2]=c[a+116>>2];c[b+68>>2]=c[a+120>>2];n=d;i=f;return n|0}function Vc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=i;c[b+4>>2]=a;a=Uc(a,c[b>>2]|0,d)|0;i=e;return a|0}function Wc(a,b){a=a|0;b=b|0;a=i;b=c[b>>2]|0;if(b)zd(b);i=a;return}function Xc(a){a=a|0;return}function Yc(a,b,c){a=a|0;b=b|0;c=c|0;return}function Zc(a){a=a|0;var b=0,d=0;b=i;d=a+8|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+16|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+64|0;c[d>>2]=-1;c[d+4>>2]=-1;d=a+72|0;c[d>>2]=0;c[d+4>>2]=0;d=a+32|0;c[a>>2]=0;c[d+0>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;i=b;return}function _c(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0;g=a+16|0;c[a+12>>2]=b;c[a+20>>2]=b+e;h=b+1|0;c[g>>2]=h;e=(d[b>>0]|0)<<18;c[a>>2]=e;f=b+2|0;c[g>>2]=f;e=(d[h>>0]|0)<<10|e;c[a>>2]=e;c[g>>2]=b+3;c[a>>2]=(d[f>>0]|0)<<2|e|2;c[a+4>>2]=510;return}function $c(){var b=0,e=0,f=0,g=0,h=0,j=0;b=i;if(!(c[718]|0))e=0;else{i=b;return}while(1)if(e){g=(e&65280|0)==0;a[2880+e>>0]=(g?8:0)-(d[4680+(g?e:e>>>8)>>0]|0);e=e+1|0;if((e|0)==512){e=0;break}else continue}else{a[2880]=9;e=1;continue}while(1){f=e<<1;g=0;do{j=a[4224+(e<<2)+g>>0]|0;h=(g<<7)+f|0;a[(h|1)+3392>>0]=j;a[h+3392>>0]=j;g=g+1|0}while((g|0)!=4);j=(d[4480+e>>0]|0)<<1;a[f+4032>>0]=j;a[f+4033>>0]=j|1;if(e){h=(d[4544+e>>0]|0)<<1;j=128-f|0;a[j+3903>>0]=h;a[j+3902>>0]=h|1;e=e+1|0;if((e|0)==64)break;else continue}else{e=128-f|0;a[e+3903>>0]=1;a[e+3902>>0]=0;e=1;continue}}g=4160|0;f=4608|0;e=g+63|0;do{a[g>>0]=a[f>>0]|0;g=g+1|0;f=f+1|0}while((g|0)<(e|0));c[718]=1;i=b;return}function ad(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=i;f=a+8|0;h=c[f>>2]|0;g=c[a+16>>2]|0;a=(c[a>>2]|0)+(h>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(h&7)>>>(32-b|0);b=h+b|0;c[f>>2]=g>>>0>b>>>0?b:g;i=e;return a|0}function bd(a,b){a=a|0;b=b|0;var e=0,f=0;e=i;f=c[a+8>>2]|0;a=(c[a>>2]|0)+(f>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(f&7)>>>(32-b|0);i=e;return a|0}function cd(a,b){a=a|0;b=b|0;var d=0;d=a+8|0;a=c[a+16>>2]|0;b=(c[d>>2]|0)+b|0;c[d>>2]=a>>>0>b>>>0?b:a;return}function dd(a){a=a|0;var b=0,e=0,f=0;e=a+8|0;f=c[e>>2]|0;b=(d[(c[a>>2]|0)+(f>>>3)>>0]|0)<<(f&7)>>>7&1;c[e>>2]=((f|0)<(c[a+16>>2]|0)&1)+f;return b|0}function ed(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;if(!b){j=0;i=e;return j|0}f=a+8|0;h=c[f>>2]|0;g=c[a+16>>2]|0;j=c[a>>2]|0;a=j+(h>>>3)|0;a=(Xd(d[a>>0]|d[a+1>>0]<<8|d[a+2>>0]<<16|d[a+3>>0]<<24|0)|0)<<(h&7);if((b|0)<26){j=h+b|0;c[f>>2]=g>>>0>j>>>0?j:g;j=a>>>(32-b|0);i=e;return j|0}else{k=h+16|0;k=g>>>0>k>>>0?k:g;c[f>>2]=k;h=b+ -16|0;j=j+(k>>>3)|0;j=(Xd(d[j>>0]|d[j+1>>0]<<8|d[j+2>>0]<<16|d[j+3>>0]<<24|0)|0)<<(k&7)>>>(48-b|0);b=k+h|0;c[f>>2]=g>>>0>b>>>0?b:g;j=j|a>>>16<>2]=c[a+0>>2];c[e+4>>2]=c[a+4>>2];c[e+8>>2]=c[a+8>>2];c[e+12>>2]=c[a+12>>2];c[e+16>>2]=c[a+16>>2];e=ed(e,32)|0;f=e>>>0>65535;e=f?e>>>16:e;f=f?16:0;if(e&65280){f=f|8;e=e>>>8}j=31-f-(d[4680+e>>0]|0)|0;g=a+8|0;f=c[g>>2]|0;e=0-f|0;h=(c[a+16>>2]|0)-f|0;if((j|0)<(e|0)){h=e;h=h+f|0;c[g>>2]=h;j=j+1|0;j=ed(a,j)|0;j=j+ -1|0;i=b;return j|0}h=(h|0)<(j|0)?h:j;h=h+f|0;c[g>>2]=h;j=j+1|0;j=ed(a,j)|0;j=j+ -1|0;i=b;return j|0}function gd(a){a=a|0;var b=0;b=i;a=fd(a)|0;if(!(a&1)){a=0-(a>>>1)|0;i=b;return a|0}else{a=(a+1|0)>>>1;i=b;return a|0}return 0}function hd(a){a=a|0;var b=0,d=0,e=0;b=i;d=c[1168]|0;if((d+ -32|0)>>>0>=a>>>0){e=Sd(a)|0;if((e|0)==0&(a|0)==0)if((d|0)==32)e=0;else e=Sd(1)|0}else e=0;i=b;return e|0}function id(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;f=$(d,b)|0;if((d|b)>>>0>65535&(d|0)!=0?((f>>>0)/(d>>>0)|0|0)!=(b|0):0){Td(a);d=0;i=e;return d|0}if(((c[1168]|0)+ -32|0)>>>0>>0)b=0;else b=Ud(a,((f|0)==0&1)+f|0)|0;if((b|0)!=0|(f|0)==0){d=b;i=e;return d|0}Td(a);d=0;i=e;return d|0}function jd(a){a=a|0;var b=0;b=i;Td(a);i=b;return}function kd(a){a=a|0;var b=0;b=i;Td(c[a>>2]|0);c[a>>2]=0;i=b;return}function ld(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;if(((d|0)!=0?(2147483647/(d>>>0)|0)>>>0>b>>>0:0)?(f=$(d,b)|0,((c[1168]|0)+ -32|0)>>>0>=f>>>0):0)a=Ud(a,((f|0)==0&1)+f|0)|0;else a=0;i=e;return a|0}function md(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=i;e=id(c[a>>2]|0,b,d)|0;c[a>>2]=e;i=f;return((e|0)!=0|(b|0)==0|(d|0)==0?0:-12)|0}function nd(a){a=a|0;var b=0,c=0;c=i;b=hd(a)|0;if(b)ae(b|0,0,a|0)|0;i=c;return b|0}function od(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=i;if((c[b>>2]|0)>>>0>d>>>0){i=e;return}f=((d*17|0)>>>4)+32|0;d=f>>>0>d>>>0?f:d;Td(c[a>>2]|0);f=hd(d)|0;c[a>>2]=f;c[b>>2]=(f|0)==0?0:d;i=e;return}function pd(a,b){a=a|0;b=b|0;var c=0;c=i;if((b|0)!=0?(2147483647/(b>>>0)|0)>>>0>a>>>0:0)b=hd($(b,a)|0)|0;else b=0;i=c;return b|0}function qd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;if(((b|0)!=0?(2147483647/(b>>>0)|0)>>>0>a>>>0:0)?(e=$(b,a)|0,d=hd(e)|0,(d|0)!=0):0)ae(d|0,0,e|0)|0;else d=0;i=c;return d|0}function rd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0;g=i;i=i+16|0;h=g;j=nd(24)|0;c[h>>2]=j;if(!j){f=0;i=g;return f|0}c[j>>2]=a;c[j+4>>2]=b;c[j+12>>2]=(d|0)!=0?d:7;c[j+16>>2]=e;c[j+8>>2]=1;if(f&1){f=(c[h>>2]|0)+20|0;c[f>>2]=c[f>>2]|1}j=nd(12)|0;if(!j){kd(h);f=0;i=g;return f|0}else{c[j>>2]=c[h>>2];c[j+4>>2]=a;c[j+8>>2]=b;f=j;i=g;return f|0}return 0}function sd(a,b){a=a|0;b=b|0;a=i;jd(b);i=a;return}function td(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;e=hd(a)|0;c[d>>2]=e;if(e){a=rd(e,a,7,0,0)|0;if(!a){kd(d);a=0}}else a=0;i=b;return a|0}function ud(a){a=a|0;var b=0,d=0;b=i;d=td(a)|0;if(!d){d=0;i=b;return d|0}ae(c[d+4>>2]|0,0,a|0)|0;i=b;return d|0}function vd(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;e=b;d=nd(12)|0;if(!d){e=0;i=b;return e|0}c[d+0>>2]=c[a+0>>2];c[d+4>>2]=c[a+4>>2];c[d+8>>2]=c[a+8>>2];f=(c[a>>2]|0)+8|0;a=c[f>>2]|0;c[f>>2]=a+1;c[e>>2]=a+1;e=d;i=b;return e|0}function wd(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;e=b+4|0;d=b;if(!a){i=b;return}f=c[a>>2]|0;if(!f){i=b;return}f=c[f>>2]|0;c[d>>2]=f;kd(a);a=f+8|0;f=c[a>>2]|0;c[a>>2]=f+ -1;c[e>>2]=f+ -1;if(c[e>>2]|0){i=b;return}f=c[d>>2]|0;Ca[c[f+12>>2]&7](c[f+16>>2]|0,c[f>>2]|0);kd(d);i=b;return}function xd(){var a=0,b=0,d=0;a=i;b=nd(400)|0;if(!b){b=0;i=a;return b|0}ae(b|0,0,400)|0;d=b+136|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+144|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+128|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+360|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=b+376|0;c[d>>2]=0;c[d+4>>2]=0;d=b+368|0;c[d>>2]=-1;c[d+4>>2]=-1;c[b+392>>2]=-1;c[b+80>>2]=1;c[b+120>>2]=0;c[b+124>>2]=1;c[b+76>>2]=-1;c[b+344>>2]=2;c[b+348>>2]=2;c[b+352>>2]=2;c[b+340>>2]=0;c[b+356>>2]=0;i=a;return b|0}function yd(a){a=a|0;var b=0,d=0;b=i;if((a|0)!=0?(d=c[a>>2]|0,(d|0)!=0):0){zd(d);kd(a)}i=b;return}function zd(a){a=a|0;var b=0,d=0;b=i;wd(a+304|0);wd(a+308|0);wd(a+312|0);wd(a+316|0);wd(a+320|0);wd(a+324|0);wd(a+328|0);wd(a+332|0);ae(a|0,0,400)|0;d=a+136|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+144|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+128|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+360|0;c[d>>2]=0;c[d+4>>2]=-2147483648;d=a+376|0;c[d>>2]=0;c[d+4>>2]=0;d=a+368|0;c[d>>2]=-1;c[d+4>>2]=-1;c[a+392>>2]=-1;c[a+80>>2]=1;c[a+120>>2]=0;c[a+124>>2]=1;c[a+76>>2]=-1;c[a+344>>2]=2;c[a+348>>2]=2;c[a+352>>2]=2;c[a+340>>2]=0;c[a+356>>2]=0;i=b;return}function Ad(a,b){a=a|0;b=b|0;var d=0;d=i;ce(a|0,b|0,400)|0;ae(b|0,0,400)|0;a=b+136|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+144|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+128|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+360|0;c[a>>2]=0;c[a+4>>2]=-2147483648;a=b+376|0;c[a>>2]=0;c[a+4>>2]=0;a=b+368|0;c[a>>2]=-1;c[a+4>>2]=-1;c[b+392>>2]=-1;c[b+80>>2]=1;c[b+120>>2]=0;c[b+124>>2]=1;c[b+76>>2]=-1;c[b+344>>2]=2;c[b+348>>2]=2;c[b+352>>2]=2;c[b+340>>2]=0;c[b+356>>2]=0;i=d;return}function Bd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;c[a+76>>2]=c[b+76>>2];c[a+64>>2]=c[b+64>>2];c[a+68>>2]=c[b+68>>2];c[a+388>>2]=c[b+388>>2];j=b+296|0;h=c[j+4>>2]|0;f=a+296|0;c[f>>2]=c[j>>2];c[f+4>>2]=h;c[a+72>>2]=c[b+72>>2];f=c[b+304>>2]|0;if(!f)sa();else{e=f;g=0}while(1){if((e|0)!=0?(j=vd(e)|0,c[a+(g<<2)+304>>2]=j,(j|0)==0):0){e=5;break}g=g+1|0;if(g>>>0>=8){e=8;break}e=c[b+(g<<2)+304>>2]|0}if((e|0)==5){zd(a);j=-12;i=d;return j|0}else if((e|0)==8){c[a+0>>2]=c[b+0>>2];c[a+4>>2]=c[b+4>>2];c[a+8>>2]=c[b+8>>2];c[a+12>>2]=c[b+12>>2];c[a+16>>2]=c[b+16>>2];c[a+20>>2]=c[b+20>>2];c[a+24>>2]=c[b+24>>2];c[a+28>>2]=c[b+28>>2];j=a+32|0;h=b+32|0;c[j+0>>2]=c[h+0>>2];c[j+4>>2]=c[h+4>>2];c[j+8>>2]=c[h+8>>2];c[j+12>>2]=c[h+12>>2];c[j+16>>2]=c[h+16>>2];c[j+20>>2]=c[h+20>>2];c[j+24>>2]=c[h+24>>2];c[j+28>>2]=c[h+28>>2];j=0;i=d;return j|0}return 0}function Cd(a){a=a|0;var b=0,d=0,e=0,f=0;d=i;e=0;while(1){f=e+1|0;if((c[4936+(e*24|0)>>2]|0)==(a|0))break;if(f>>>0<4)e=f;else{e=0;b=5;break}}if((b|0)==5){i=d;return e|0}f=4940+(e*24|0)|0;i=d;return f|0}function Dd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;g=(c[b+16>>2]|0)==0?1:3;if((g|0)>(e|0)){b=c[b>>2]|0;c[d>>2]=c[b+(e<<2)+32>>2];b=c[b+(e<<2)>>2]|0;i=f;return b|0}if((a[b+20>>0]|0)!=0&(g|0)==(e|0)){b=c[b+4>>2]|0;c[d>>2]=c[b+32>>2];b=c[b>>2]|0;i=f;return b|0}else{c[d>>2]=0;b=0;i=f;return b|0}return 0}function Ed(b,e){b=b|0;e=e|0;var f=0,g=0,h=0;f=i;if(!(c[b>>2]|0)){h=-1;i=f;return h|0}c[e>>2]=c[b+8>>2];c[e+4>>2]=c[b+12>>2];c[e+8>>2]=c[b+16>>2];g=b+22|0;if(!(a[b+20>>0]|0))h=0;else h=(a[g>>0]|0)==0;c[e+12>>2]=h&1;c[e+24>>2]=d[b+24>>0];c[e+28>>2]=d[g>>0];c[e+32>>2]=d[b+23>>0];c[e+16>>2]=c[b+28>>2];c[e+20>>2]=d[b+21>>0];h=0;i=f;return h|0}function Fd(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;h=i;f=c[b+8>>2]|0;g=b+44|0;l=c[g>>2]|0;if(l>>>0>=(c[b+12>>2]|0)>>>0){v=-1;i=h;return v|0}m=(c[b+56>>2]|0)+($(c[b+72>>2]|0,l)|0)|0;j=b+40|0;k=(d[j>>0]|0)+3|0;n=c[b+16>>2]|0;if(!n)Ma[c[b+212>>2]&7](b+164|0,e,m,0,0,f,k);else if((n|0)==1){t=l>>1;o=(t|0)%8|0;u=b+88|0;s=c[u>>2]|0;r=b+96|0;n=b+160|0;q=c[n>>2]|0;v=b+21|0;p=d[v>>0]|0;if(!(l&1)){Gd(s,r,f,o,q,p,0);Gd(c[b+92>>2]|0,b+128|0,f,o,c[n>>2]|0,d[v>>0]|0,0)}else{Gd(s,r,f,o,q,p,1);Gd(c[b+92>>2]|0,b+128|0,f,o,c[n>>2]|0,d[v>>0]|0,1);s=(o+5|0)%8|0;r=t+5|0;t=c[b+52>>2]|0;t=(r|0)<(t|0)?r:t+ -1|0;r=(c[b+60>>2]|0)+($(t,c[b+76>>2]|0)|0)|0;t=(c[b+64>>2]|0)+($(c[b+80>>2]|0,t)|0)|0;v=b+48|0;ce(c[b+(s<<2)+96>>2]|0,r|0,c[v>>2]|0)|0;ce(c[b+(s<<2)+128>>2]|0,t|0,c[v>>2]|0)|0}Ma[c[b+212>>2]&7](b+164|0,e,m,c[u>>2]|0,c[b+92>>2]|0,f,k)}else if((n|0)==2){v=(c[b+60>>2]|0)+($(c[b+76>>2]|0,l)|0)|0;s=(c[b+64>>2]|0)+($(c[b+80>>2]|0,l)|0)|0;u=b+88|0;t=b+21|0;Hd(c[u>>2]|0,v,f,d[t>>0]|0);v=b+92|0;Hd(c[v>>2]|0,s,f,d[t>>0]|0);Ma[c[b+212>>2]&7](b+164|0,e,m,c[u>>2]|0,c[v>>2]|0,f,k)}else if((n|0)==3){u=(c[b+60>>2]|0)+($(c[b+76>>2]|0,l)|0)|0;v=(c[b+64>>2]|0)+($(c[b+80>>2]|0,l)|0)|0;Ma[c[b+212>>2]&7](b+164|0,e,m,u,v,f,k)}else{v=-1;i=h;return v|0}a:do if(!(a[b+22>>0]|0)){if(a[j>>0]|0){if(!(a[b+20>>0]|0)){if((f|0)<=0)break;b=e+3|0;e=0;while(1){a[b>>0]=-1;e=e+1|0;if((e|0)==(f|0))break a;else b=b+4|0}}j=c[b+68>>2]|0;k=$(c[b+84>>2]|0,l)|0;o=e+3|0;if((c[b+204>>2]|0)==8){if((f|0)>0){l=0;while(1){a[o>>0]=a[j+(l+k)>>0]|0;l=l+1|0;if((l|0)==(f|0))break;else o=o+4|0}}}else{m=c[b+172>>2]|0;l=c[b+168>>2]|0;n=c[b+164>>2]|0;if((f|0)>0){p=0;while(1){a[o>>0]=($(d[j+(p+k)>>0]|0,m)|0)+l>>n;p=p+1|0;if((p|0)==(f|0))break;else o=o+4|0}}}if(a[b+24>>0]|0){if(!(c[1264]|0)){c[1264]=1;b=1;do{c[5064+(b<<2)>>2]=(((b|0)/2|0)+16711808|0)/(b|0)|0;b=b+1|0}while((b|0)!=256)}if((f|0)>0){b=0;while(1){k=a[e+3>>0]|0;if(!(k<<24>>24)){a[e>>0]=-1;a[e+1>>0]=-1;a[e+2>>0]=-1}else{j=c[5064+((k&255)<<2)>>2]|0;l=a[e>>0]|0;if((l&255)<(k&255))l=(($(l&255,j)|0)+32768|0)>>>16&255;else l=-1;a[e>>0]=l;l=e+1|0;m=a[l>>0]|0;if((m&255)<(k&255))m=(($(m&255,j)|0)+32768|0)>>>16&255;else m=-1;a[l>>0]=m;l=e+2|0;m=a[l>>0]|0;if((m&255)<(k&255))j=(($(m&255,j)|0)+32768|0)>>>16&255;else j=-1;a[l>>0]=j}b=b+1|0;if((b|0)==(f|0))break;else e=e+4|0}}}}}else{m=c[b+68>>2]|0;l=$(c[b+84>>2]|0,l)|0;b=c[b+204>>2]|0;n=1<0;if(q){o=e;p=0;while(1){u=d[m+(p+l)>>0]|0;a[o>>0]=($(d[o>>0]|0,u)|0)+n>>b;v=o+1|0;a[v>>0]=($(d[v>>0]|0,u)|0)+n>>b;v=o+2|0;a[v>>0]=($(d[v>>0]|0,u)|0)+n>>b;p=p+1|0;if((p|0)==(f|0))break;else o=o+k|0}}if(!((a[j>>0]|0)==0|q^1)){e=e+3|0;b=0;while(1){a[e>>0]=-1;b=b+1|0;if((b|0)==(f|0))break;else e=e+4|0}}}while(0);c[g>>2]=(c[g>>2]|0)+1;v=0;i=h;return v|0}function Gd(e,f,g,h,j,k,l){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;m=i;n=c[f+((h+5&7)<<2)>>2]|0;o=c[f+((h+6&7)<<2)>>2]|0;s=c[f+((h+7&7)<<2)>>2]|0;r=c[f+((h&7)<<2)>>2]|0;q=c[f+((h+1&7)<<2)>>2]|0;p=c[f+((h+2&7)<<2)>>2]|0;h=c[f+((h+3&7)<<2)>>2]|0;t=k+ -8|0;f=(g+1|0)/2|0;u=(g|0)>0;if(!l){if(u){l=0;do{z=($(d[o+l>>0]|0,-6)|0)+(d[n+l>>0]<<1)|0;z=z+((d[s+l>>0]|0)*18|0)+((d[r+l>>0]|0)*57|0)+($(d[q+l>>0]|0,-10)|0)|0;b[j+(l+3<<1)>>1]=z+(d[p+l>>0]<<2)-(d[h+l>>0]|0)>>t;l=l+1|0}while((l|0)<(f|0))}}else if(u){l=0;do{z=(d[o+l>>0]<<2)-(d[n+l>>0]|0)+($(d[s+l>>0]|0,-10)|0)|0;z=z+((d[r+l>>0]|0)*57|0)+((d[q+l>>0]|0)*18|0)+($(d[p+l>>0]|0,-6)|0)|0;b[j+(l+3<<1)>>1]=z+(d[h+l>>0]<<1)>>t;l=l+1|0}while((l|0)<(f|0))}s=j+6|0;n=b[s>>1]&255;b[j>>1]=n;v=j+2|0;b[v>>1]=n;u=j+4|0;b[u>>1]=n;n=b[j+(f+2<<1)>>1]&255;b[j+(f+3<<1)>>1]=n;b[j+(f+4<<1)>>1]=n;b[j+(f+5<<1)>>1]=n;b[j+(f+6<<1)>>1]=n;n=(1<>1]|0;v=b[v>>1]|0;u=b[u>>1]|0;f=b[s>>1]|0;l=b[j+8>>1]|0;h=b[j+10>>1]|0;if((g|0)>1){q=g+ -2|0;p=q>>>1;r=p<<1;x=e;while(1){w=b[s+6>>1]|0;y=f*57|0;z=(h<<2)+o+($(l,-10)|0)+y+(u*18|0)+($(v,-6)|0)+(t<<1)-w>>k;if((z|0)<0)z=0;else z=((z|0)>(n|0)?n:z)&255;a[x>>0]=z;t=($(h,-6)|0)+o+(l*18|0)+y+($(u,-10)|0)-t+(v<<2)+(w<<1)>>k;if((t|0)<0)t=0;else t=((t|0)>(n|0)?n:t)&255;a[x+1>>0]=t;g=g+ -2|0;if((g|0)<=1)break;else{B=h;A=l;y=f;z=u;t=v;h=w;x=x+2|0;s=s+2|0;l=B;f=A;u=y;v=z}}t=v;v=u;u=f;f=l;l=h;h=w;e=e+(r+2)|0;g=q-r|0;s=j+(p+4<<1)|0}if(!g){i=m;return}j=(h<<2)+o+($(l,-10)|0)+(f*57|0)+(u*18|0)+($(v,-6)|0)+(t<<1)-(b[s+6>>1]|0)>>k;if((j|0)<0)j=0;else j=((j|0)>(n|0)?n:j)&255;a[e>>0]=j;i=m;return}function Hd(b,c,e,f){b=b|0;c=c|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;g=i;o=(e+1|0)/2|0;h=hd(o+7|0)|0;l=h+3|0;ce(l|0,c|0,o|0)|0;ae(h|0,a[c>>0]|0,3)|0;ae(h+(o+3)|0,a[c+(o+ -1)>>0]|0,4)|0;c=(1<>0]|0;r=d[h+1>>0]|0;m=d[h+2>>0]|0;q=d[l>>0]|0;p=d[h+4>>0]|0;n=d[h+5>>0]|0;if((e|0)>1){j=e+ -2|0;f=j>>>1;k=f<<1;t=b;while(1){s=d[l+3>>0]|0;u=q*57|0;v=(n<<2)+32+($(p,-10)|0)+u+(m*18|0)+($(r,-6)|0)+(o<<1)-s>>6;if((v|0)<0)v=0;else v=((v|0)>(c|0)?c:v)&255;a[t>>0]=v;o=($(n,-6)|0)+32+(p*18|0)+u+($(m,-10)|0)-o+(r<<2)+(s<<1)>>6;if((o|0)<0)o=0;else o=((o|0)>(c|0)?c:o)&255;a[t+1>>0]=o;e=e+ -2|0;if((e|0)<=1)break;else{x=n;w=p;u=q;v=m;o=r;n=s;t=t+2|0;l=l+1|0;p=x;q=w;m=u;r=v}}o=r;r=m;m=q;q=p;p=n;n=s;b=b+(k+2)|0;e=j-k|0;l=h+(f+4)|0}if(!e){jd(h);i=g;return}f=(n<<2)+32+($(p,-10)|0)+(q*57|0)+(m*18|0)+($(r,-6)|0)+(o<<1)-(d[l+3>>0]|0)>>6;if((f|0)<0)c=0;else c=((f|0)>(c|0)?c:f)&255;a[b>>0]=c;jd(h);i=g;return}function Id(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0,t=0.0,u=0,v=0,w=0,x=0,y=0,z=0.0,A=0.0,B=0.0;f=i;if(!(c[b>>2]|0)){w=-1;i=f;return w|0}g=b+44|0;if((c[g>>2]|0)>-1|e>>>0>1){w=-1;i=f;return w|0}a[b+40>>0]=(e|0)==1&1;k=b+41|0;a[k>>0]=0;c[b+56>>2]=Dd(b,b+72|0,0)|0;e=b+16|0;if(!(c[e>>2]|0))m=1;else{c[b+60>>2]=Dd(b,b+76|0,1)|0;c[b+64>>2]=Dd(b,b+80|0,2)|0;m=3}if(!(a[b+20>>0]|0))c[b+68>>2]=0;else c[b+68>>2]=Dd(b,b+84|0,m)|0;if(((c[e>>2]|0)+ -1|0)>>>0<2?(w=b+8|0,v=c[w>>2]|0,l=b+48|0,c[l>>2]=(v+1|0)/2|0,j=b+52|0,c[j>>2]=((c[b+12>>2]|0)+1|0)/2|0,c[b+88>>2]=hd(v)|0,c[b+92>>2]=hd(c[w>>2]|0)|0,(c[e>>2]|0)==1):0){o=c[l>>2]|0;m=0;do{c[b+(m<<2)+96>>2]=hd(o)|0;c[b+(m<<2)+128>>2]=hd(c[l>>2]|0)|0;m=m+1|0;o=c[l>>2]|0}while((m|0)!=8);c[b+160>>2]=hd((o<<1)+14|0)|0;m=b+60|0;o=b+76|0;s=b+64|0;u=b+80|0;v=0;do{w=(v|0)>4?v+ -8|0:v;if((w|0)<0)w=0;else{x=c[j>>2]|0;w=(w|0)<(x|0)?w:x+ -1|0}y=(c[m>>2]|0)+($(c[o>>2]|0,w)|0)|0;x=(c[s>>2]|0)+($(c[u>>2]|0,w)|0)|0;ce(c[b+(v<<2)+96>>2]|0,y|0,c[l>>2]|0)|0;ce(c[b+(v<<2)+128>>2]|0,x|0,c[l>>2]|0)|0;v=v+1|0}while((v|0)!=8)}j=d[b+21>>0]|0;y=(a[k>>0]|0)!=0?16:8;m=b+28|0;s=c[m>>2]|0;l=a[b+23>>0]|0;k=l&255;o=30-y|0;n=+((1<>24!=0;if(l){y=j+ -8|0;q=n/+(224<>2]=ra(+(q*B*2.0))|0;z=1.0-t;A=z-r;c[b+188>>2]=ra(+(q*(t*2.0*z/A)))|0;c[b+192>>2]=ra(+(q*(r*2.0*B/A)))|0;c[b+196>>2]=ra(+(q*z*2.0))|0}h=ra(+p)|0;c[b+172>>2]=h;c[b+164>>2]=o;s=1<>2]=s;c[b+200>>2]=1<>2]=y;y=$(y,-16<>2]=y+(c[o>>2]|0)}else{c[b+176>>2]=h;c[b+180>>2]=s}c[b+204>>2]=j;c[b+208>>2]=k;if(!(c[e>>2]|0))c[b+212>>2]=4;else c[b+212>>2]=c[5032+(c[m>>2]<<2)>>2];c[g>>2]=0;y=0;i=f;return y|0}function Jd(){var a=0,b=0;a=i;b=nd(216)|0;if(!b)b=0;i=a;return b|0}function Kd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+48|0;m=f+36|0;l=f;if((e|0)<6){u=-1;i=f;return u|0}if((a[d>>0]|0)!=66){u=-1;i=f;return u|0}if((a[d+1>>0]|0)!=80){u=-1;i=f;return u|0}if((a[d+2>>0]|0)!=71){u=-1;i=f;return u|0}if((a[d+3>>0]|0)!=-5){u=-1;i=f;return u|0}t=a[d+4>>0]|0;u=t&255;n=u>>>5;k=l+8|0;c[k>>2]=n;if(t<<24>>24<0){u=-1;i=f;return u|0}t=(u&15)+8|0;a[l+13>>0]=t;if((t&255)>>>0>14){u=-1;i=f;return u|0}q=a[d+5>>0]|0;j=q&255;p=j>>>4;h=l+20|0;c[h>>2]=p;o=j&8;r=j>>>2&1;g=l+16|0;a[g>>0]=j>>>1&1;j=l+12|0;a[j>>0]=0;s=l+14|0;a[s>>0]=0;t=l+15|0;a[t>>0]=0;if(!(u&16))if(!r)r=0;else{a[j>>0]=1;a[s>>0]=1;r=1}else{a[j>>0]=1;a[t>>0]=r;r=0}if((q&255)>79){u=-1;i=f;return u|0}if(!((n|0)!=0|(p|0)==0)){u=-1;i=f;return u|0}if(r<<24>>24!=0&(n|0)==0){u=-1;i=f;return u|0}n=Nd(l,d+6|0,e+ -6|0)|0;if((n|0)<0){u=-1;i=f;return u|0}n=n+6|0;p=l+4|0;q=Nd(p,d+n|0,e-n|0)|0;if((q|0)<0){u=-1;i=f;return u|0}q=q+n|0;if(!(c[l>>2]|0)){u=-1;i=f;return u|0}if(!(c[p>>2]|0)){u=-1;i=f;return u|0}n=l+24|0;r=Nd(n,d+q|0,e-q|0)|0;if((r|0)<0){u=-1;i=f;return u|0}s=r+q|0;c[m>>2]=0;q=(o|0)!=0;do if(q){o=Nd(m,d+s|0,e-s|0)|0;if((o|0)<0){u=-1;i=f;return u|0}else{s=o+s|0;break}}while(0);o=l+28|0;c[o>>2]=0;do if(a[j>>0]|0){r=Nd(o,d+s|0,e-s|0)|0;if((r|0)<0){u=-1;i=f;return u|0}else{s=r+s|0;break}}while(0);c[l+32>>2]=0;do if(q){m=(c[m>>2]|0)+s|0;if((m|0)>(e|0))b=-1;else break;i=f;return b|0}else m=s;while(0);if((m|0)<0){u=m;i=f;return u|0}l=c[l>>2]|0;p=c[p>>2]|0;k=c[k>>2]|0;t=c[j>>2]|0;j=t&255;u=c[h>>2]|0;s=(t&65535)>>>8;h=s&65535;r=b+8|0;c[r>>2]=l;q=b+12|0;c[q>>2]=p;c[b+16>>2]=k;a[b+20>>0]=j;a[b+24>>0]=t>>>24;a[b+22>>0]=t>>>16;a[b+23>>0]=a[g>>0]|0;c[b+28>>2]=u;a[b+21>>0]=s;g=b+36|0;c[g>>2]=0;s=c[n>>2]|0;n=s+m|0;a:do if(n>>>0>e>>>0)d=b;else{m=Ld(d+m|0,s,l,p,k,h)|0;c[b>>2]=m;if(!m){d=b;break}if((c[m+64>>2]|0)<(c[r>>2]|0)){d=b;break}if((c[m+68>>2]|0)<(c[q>>2]|0)){d=b;break}switch(c[m+76>>2]|0){case 4:case 56:{if((k|0)!=2){d=b;break a}break};case 5:case 58:{if((k|0)!=3){d=b;break a}break};case 8:case 32:{if(k){d=b;break a}break};case 0:case 54:{if((k|0)!=1){d=b;break a}break};default:{d=b;break a}}if(j<<24>>24){j=c[o>>2]|0;if((j+n|0)>>>0>e>>>0){d=b;break}u=Ld(d+n|0,j,l,p,0,h)|0;c[b+4>>2]=u;if(!u){d=b;break}}c[b+44>>2]=-1;u=0;i=f;return u|0}while(0);if(c[d>>2]|0)yd(d);b=b+4|0;if(c[b>>2]|0)yd(b);c[g>>2]=0;u=-1;i=f;return u|0}function Ld(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;k=i;i=i+96|0;n=k+88|0;o=k;l=k+84|0;q=k+80|0;p=Nd(q,b,d)|0;if((p|0)<0){b=0;i=k;return b|0}r=d-p|0;s=c[q>>2]|0;if(s>>>0>r>>>0){b=0;i=k;return b|0}d=s+10|0;q=hd(d)|0;a[q>>0]=g;a[q+1>>0]=e>>>24;a[q+2>>0]=e>>>16;a[q+3>>0]=e>>>8;a[q+4>>0]=e;a[q+5>>0]=f>>>24;a[q+6>>0]=f>>>16;a[q+7>>0]=f>>>8;a[q+8>>0]=f;a[q+9>>0]=h+248;ce(q+10|0,b+p|0,s|0)|0;g=b+(s+p)|0;r=r-s|0;p=hd((d<<1)+10-s+r|0)|0;a[p>>0]=0;a[p+1>>0]=0;a[p+2>>0]=0;a[p+3>>0]=1;a[p+4>>0]=96;a[p+5>>0]=1;if((d|0)>0){f=0;s=6;while(1){e=f+1|0;h=a[q+f>>0]|0;if((e|0)<(d|0)&h<<24>>24==0)if(!(a[q+e>>0]|0)){a[p+s>>0]=0;a[p+(s+1)>>0]=0;a[p+(s+2)>>0]=3;e=f+2|0;s=s+3|0}else{h=0;j=7}else j=7;if((j|0)==7){j=0;a[p+s>>0]=h;s=s+1|0}if((e|0)<(d|0))f=e;else break}if(!s){s=0;j=11}else j=10}else{s=6;j=10}if((j|0)==10)if(!(a[p+(s+ -1)>>0]|0))j=11;if((j|0)==11){a[p+s>>0]=-128;s=s+1|0}jd(q);a[p+s>>0]=0;a[p+(s+1)>>0]=0;a[p+(s+2)>>0]=0;b=s+4|0;a[p+(s+3)>>0]=1;ce(p+b|0,g|0,r|0)|0;r=b+r|0;Zc(o);g=Qc(1416)|0;if(!g)wa(1);if(c[358]&8){b=g+84|0;c[b>>2]=c[b>>2]|65536}b=g+688|0;c[b>>2]=c[b>>2]|1;if((Kc(g,1416,0)|0)<0)wa(1);s=xd()|0;c[l>>2]=s;if(!s){b=0;i=k;return b|0}q=o+28|0;c[q>>2]=r;d=o+24|0;c[d>>2]=p;if((r|0)>0){r=s;s=0;while(1){r=Rc(g,r,n,o)|0;if((r|0)<0){j=26;break}m=((c[n>>2]|0)!=0&1)+s|0;s=c[d>>2]|0;e=c[q>>2]|0;if(s){e=e-r|0;c[q>>2]=e;c[d>>2]=s+r}if((e|0)<=0)break;r=c[l>>2]|0;s=m}if((j|0)==26)wa(1);Lc(g)|0;jd(g);jd(p);if(m){b=c[l>>2]|0;i=k;return b|0}}else{Lc(g)|0;jd(g);jd(p)}yd(l);b=0;i=k;return b|0}function Md(a){a=a|0;var b=0,d=0;b=i;jd(c[a+88>>2]|0);jd(c[a+92>>2]|0);d=0;do{jd(c[a+(d<<2)+96>>2]|0);jd(c[a+(d<<2)+128>>2]|0);d=d+1|0}while((d|0)!=8);jd(c[a+160>>2]|0);if(c[a>>2]|0)yd(a);d=a+4|0;if(!(c[d>>2]|0)){jd(a);i=b;return}yd(d);jd(a);i=b;return}function Nd(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0;g=i;if((f|0)<1){l=-1;i=g;return l|0}k=e+1|0;l=a[e>>0]|0;j=l&255;if(l<<24>>24<=-1){if(l<<24>>24==-128){l=-1;i=g;return l|0}j=j&127;while(1){if((f|0)<2){b=-1;h=10;break}l=k;k=k+1|0;l=d[l>>0]|0;j=l&127|j<<7;if(!(l&128))break;else f=f+ -1|0}if((h|0)==10){i=g;return b|0}c[b>>2]=j;h=k-e|0;if((h|0)<0){l=h;i=g;return l|0}}else{c[b>>2]=j;h=1}l=j>>>0>1073741823?-1:h;i=g;return l|0}function Od(b,e,f,g,h,j,k){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0;h=i;if((c[b+40>>2]|0)==8?(c[b+44>>2]|0)==0:0){if((j|0)>0)g=0;else{i=h;return}while(1){n=a[f+g>>0]|0;a[e>>0]=n;a[e+1>>0]=n;a[e+2>>0]=n;g=g+1|0;if((g|0)==(j|0))break;else e=e+k|0}i=h;return}l=c[b+12>>2]|0;g=c[b+16>>2]|0;b=c[b>>2]|0;if((j|0)>0)m=0;else{i=h;return}while(1){n=($(d[f+m>>0]|0,l)|0)+g>>b;if((n|0)<0)n=0;else n=(n|0)>255?-1:n&255;a[e>>0]=n;a[e+1>>0]=n;a[e+2>>0]=n;m=m+1|0;if((m|0)==(j|0))break;else e=e+k|0}i=h;return}function Pd(b,e,f,g,h,j,k){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;q=i;s=c[b+20>>2]|0;n=c[b+24>>2]|0;o=c[b+28>>2]|0;l=c[b+32>>2]|0;p=c[b+12>>2]|0;r=c[b+16>>2]|0;m=c[b>>2]|0;b=c[b+36>>2]|0;if((j|0)>0)t=0;else{i=q;return}while(1){v=$(d[f+t>>0]|0,p)|0;u=(d[g+t>>0]|0)-b|0;w=(d[h+t>>0]|0)-b|0;v=v+r|0;x=v+($(w,s)|0)>>m;if((x|0)<0)x=0;else x=(x|0)>255?-1:x&255;a[e>>0]=x;w=v-($(u,n)|0)-($(w,o)|0)>>m;if((w|0)<0)w=0;else w=(w|0)>255?-1:w&255;a[e+1>>0]=w;u=v+($(u,l)|0)>>m;if((u|0)<0)u=0;else u=(u|0)>255?-1:u&255;a[e+2>>0]=u;t=t+1|0;if((t|0)==(j|0))break;else e=e+k|0}i=q;return}function Qd(b,e,f,g,h,j,k){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0;l=i;if((c[b+40>>2]|0)==8?(c[b+44>>2]|0)==0:0){if((j|0)>0)m=0;else{i=l;return}while(1){a[e>>0]=a[h+m>>0]|0;a[e+1>>0]=a[f+m>>0]|0;a[e+2>>0]=a[g+m>>0]|0;m=m+1|0;if((m|0)==(j|0))break;else e=e+k|0}i=l;return}n=c[b+12>>2]|0;m=c[b+16>>2]|0;b=c[b>>2]|0;if((j|0)>0)o=0;else{i=l;return}while(1){p=($(d[h+o>>0]|0,n)|0)+m>>b;if((p|0)<0)p=0;else p=(p|0)>255?-1:p&255;a[e>>0]=p;p=($(d[f+o>>0]|0,n)|0)+m>>b;if((p|0)<0)p=0;else p=(p|0)>255?-1:p&255;a[e+1>>0]=p;p=($(d[g+o>>0]|0,n)|0)+m>>b;if((p|0)<0)p=0;else p=(p|0)>255?-1:p&255;a[e+2>>0]=p;o=o+1|0;if((o|0)==(j|0))break;else e=e+k|0}i=l;return}function Rd(b,e,f,g,h,j,k){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;o=i;l=c[b+12>>2]|0;m=c[b+16>>2]|0;n=c[b>>2]|0;b=c[b+36>>2]|0;if((j|0)>0)p=0;else{i=o;return}while(1){t=d[f+p>>0]|0;s=(d[g+p>>0]|0)-b|0;r=(d[h+p>>0]|0)-b|0;q=t-s|0;u=($(q+r|0,l)|0)+m>>n;if((u|0)<0)u=0;else u=(u|0)>255?-1:u&255;a[e>>0]=u;s=($(s+t|0,l)|0)+m>>n;if((s|0)<0)s=0;else s=(s|0)>255?-1:s&255;a[e+1>>0]=s;q=($(q-r|0,l)|0)+m>>n;if((q|0)<0)q=0;else q=(q|0)>255?-1:q&255;a[e+2>>0]=q;p=p+1|0;if((p|0)==(j|0))break;else e=e+k|0}i=o;return}function Sd(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;d=i;if((b|0)==0|b>>>0>2147483583){k=0;i=d;return k|0}do if(!(c[1523]|0)){e=ta(64)|0;if((e|0)==(-1|0)){k=0;i=d;return k|0}else{c[1524]=ta(0)|0;c[1523]=6088;c[1522]=6088;c[1527]=6104;c[1526]=6104;k=e+16|0;a[e+15>>0]=-86;j=c[1527]|0;c[1527]=k;c[k>>2]=6104;c[e+20>>2]=j;c[j>>2]=k;j=e+24|0;k=c[1523]|0;c[1523]=j;c[j>>2]=6088;c[e+28>>2]=k;c[k>>2]=j;break}}while(0);e=b+40&-32;h=c[1524]|0;g=c[1522]|0;k=6092|0;while(1){f=c[k>>2]|0;b=f+ -8|0;k=c[f+ -4>>2]|0;if((k|0)==6104)j=h;else j=k;j=j-b|0;if(e>>>0>>0){h=12;break}if((f|0)==(g|0)){h=10;break}k=f+4|0;if((e|0)==(j|0)){h=15;break}}do if((h|0)==10)if((ta(e+32-j|0)|0)==(-1|0)){k=0;i=d;return k|0}else{c[1524]=ta(0)|0;k=c[g+ -4>>2]|0;f=g;h=12;break}else if((h|0)==15){j=c[f>>2]|0;k=c[k>>2]|0;c[j+4>>2]=k;c[k>>2]=j}while(0);if((h|0)==12){h=b+e|0;c[f+ -4>>2]=h;c[h>>2]=b;c[b+(e|4)>>2]=k;c[k>>2]=h;h=b+(e|8)|0;k=f+4|0;j=c[k>>2]|0;c[k>>2]=h;c[h>>2]=f;c[b+(e|12)>>2]=j;c[j>>2]=h;a[b+(e+ -1)>>0]=-86;j=c[f>>2]|0;k=c[k>>2]|0;c[j+4>>2]=k;c[k>>2]=j}a[b+ -1>>0]=85;k=f;i=d;return k|0}function Td(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;if(!b){i=d;return}g=b+ -8|0;e=c[1523]|0;c[1523]=b;c[b>>2]=6088;f=b+4|0;c[f>>2]=e;c[e>>2]=b;a[b+ -9>>0]=-86;e=c[g>>2]|0;if((e|0)!=6104?(a[e+ -1>>0]|0)==-86:0){g=c[b+ -4>>2]|0;c[e+4>>2]=g;c[g>>2]=e;b=c[b>>2]|0;g=c[f>>2]|0;c[b+4>>2]=g;c[g>>2]=b}else e=g;b=c[e+4>>2]|0;if((b|0)==6104){i=d;return}if((a[b+ -1>>0]|0)!=-86){i=d;return}g=c[b>>2]|0;h=c[b+4>>2]|0;c[g+4>>2]=h;c[h>>2]=g;h=e+8|0;g=c[h>>2]|0;j=e+12|0;f=c[j>>2]|0;c[g+4>>2]=f;c[f>>2]=g;f=b+8|0;g=b+12|0;e=c[g>>2]|0;c[g>>2]=h;c[h>>2]=f;c[j>>2]=e;c[e>>2]=h;f=c[f>>2]|0;g=c[g>>2]|0;c[f+4>>2]=g;c[g>>2]=f;i=d;return}function Ud(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;do if(a){if(!b){Td(a);e=0;break}e=Sd(b)|0;if(!e)e=0;else{f=(c[a+ -4>>2]|0)-a+ -1|0;ce(e|0,a|0,(f>>>0>b>>>0?b:f)|0)|0;Td(a)}}else e=Sd(b)|0;while(0);i=d;return e|0}function Vd(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;f=i;if(!d){h=0;i=f;return h|0}while(1){g=a[b>>0]|0;h=a[c>>0]|0;if(g<<24>>24!=h<<24>>24)break;d=d+ -1|0;if(!d){b=0;e=5;break}else{b=b+1|0;c=c+1|0}}if((e|0)==5){i=f;return b|0}h=(g&255)-(h&255)|0;i=f;return h|0}function Wd(){}function Xd(a){a=a|0;return(a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function Yd(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b>>c;return a>>>c|(b&(1<>c-32|0}function Zd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;b=b-d-(c>>>0>a>>>0|0)>>>0;return(D=b,a-c>>>0|0)|0}function _d(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return(D=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function $d(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function ae(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;i=b&3;h=d|d<<8|d<<16|d<<24;g=f&~3;if(i){i=b+4-i|0;while((b|0)<(i|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function be(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b<>>32-c;return a<=4096)return ua(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function de(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){D=b>>>c;return a>>>c|(b&(1<>>c-32|0}function ee(b){b=b|0;var c=0;c=a[n+(b>>>24)>>0]|0;if((c|0)<8)return c|0;c=a[n+(b>>16&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[n+(b>>8&255)>>0]|0;if((c|0)<8)return c+16|0;return(a[n+(b&255)>>0]|0)+24|0}function fe(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return(a[m+(b>>>24)>>0]|0)+24|0}function ge(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;f=a&65535;d=b&65535;c=$(d,f)|0;e=a>>>16;d=(c>>>16)+($(d,e)|0)|0;b=b>>>16;a=$(b,f)|0;return(D=(d>>>16)+($(b,e)|0)+(((d&65535)+a|0)>>>16)|0,d+a<<16|c&65535|0)|0}function he(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;a=ge(e,f)|0;c=D;return(D=($(b,f)|0)+($(d,e)|0)+c|c&0,a|0|0)|0}function ie(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return za[a&1](b|0,c|0,d|0)|0}function je(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;Aa[a&3](b|0,c|0,d|0,e|0,f|0)}function ke(a,b){a=a|0;b=b|0;Ba[a&7](b|0)}function le(a,b,c){a=a|0;b=b|0;c=c|0;Ca[a&7](b|0,c|0)}function me(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Da[a&1](b|0,c|0,d|0,e|0,f|0,g|0)|0}function ne(a,b,c,d,e,f,g,h,i,j,k,l,m){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;Ea[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0,l|0,m|0)}function oe(a,b){a=a|0;b=b|0;return Fa[a&3](b|0)|0}function pe(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Ga[a&7](b|0,c|0,d|0)}function qe(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;Ha[a&1](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0)}function re(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Ia[a&1](b|0,c|0,d|0,e|0)|0}function se(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;Ja[a&3](b|0,c|0,d|0,e|0,f|0,g|0)}function te(a,b,c){a=a|0;b=b|0;c=c|0;return Ka[a&1](b|0,c|0)|0}function ue(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return La[a&1](b|0,c|0,d|0,e|0,f|0)|0}function ve(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;Ma[a&7](b|0,c|0,d|0,e|0,f|0,g|0,h|0)}function we(a,b,c){a=a|0;b=b|0;c=c|0;aa(0);return 0}function xe(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;aa(1)}function ye(a){a=a|0;aa(2)}function ze(a,b){a=a|0;b=b|0;aa(3)}function Ae(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;aa(4);return 0}function Be(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;aa(5)}function Ce(a){a=a|0;aa(6);return 0}function De(a,b,c){a=a|0;b=b|0;c=c|0;aa(7)}function Ee(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;aa(8)}function Fe(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;aa(9);return 0}function Ge(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;aa(10)}function He(a,b){a=a|0;b=b|0;aa(11);return 0}function Ie(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;aa(12);return 0}function Je(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;aa(13)} + + + + +// EMSCRIPTEN_END_FUNCS +var za=[we,Oc];var Aa=[xe,zc,Ac,xe];var Ba=[ye,Ob,lc,qc,rc,sc,tc,ye];var Ca=[ze,jc,mc,nc,oc,pc,Hc,sd];var Da=[Ae,Mc];var Ea=[Be,vc,wc,Be];var Fa=[Ce,Lb,Nb,Ce];var Ga=[De,fc,gc,hc,ic,kc,De,De];var Ha=[Ee,uc];var Ia=[Fe,Mb];var Ja=[Ge,ec,xc,yc];var Ka=[He,Rb];var La=[Ie,Nc];var Ma=[Je,Pd,Qd,Rd,Od,Je,Je,Je];return{_i64Subtract:Zd,_free:Td,_bpg_decoder_decode:Kd,_bpg_decoder_start:Id,_realloc:Ud,_i64Add:_d,_bpg_decoder_open:Jd,_bitshift64Ashr:Yd,_strlen:$d,_bpg_decoder_close:Md,_memset:ae,_malloc:Sd,_memcpy:ce,_bpg_decoder_get_line:Fd,_bpg_decoder_get_info:Ed,_llvm_bswap_i32:Xd,_bitshift64Shl:be,runPostSets:Wd,stackAlloc:Na,stackSave:Oa,stackRestore:Pa,setThrew:Qa,setTempRet0:Ta,getTempRet0:Ua,dynCall_iiii:ie,dynCall_viiiii:je,dynCall_vi:ke,dynCall_vii:le,dynCall_iiiiiii:me,dynCall_viiiiiiiiiiii:ne,dynCall_ii:oe,dynCall_viii:pe,dynCall_viiiiiiiii:qe,dynCall_iiiii:re,dynCall_viiiiii:se,dynCall_iii:te,dynCall_iiiiii:ue,dynCall_viiiiiii:ve}}) + + +// EMSCRIPTEN_END_ASM +(l.v,l.w,S),Ra=l._i64Subtract=Z._i64Subtract;l._free=Z._free;l._bpg_decoder_decode=Z._bpg_decoder_decode;l._bpg_decoder_start=Z._bpg_decoder_start;l._realloc=Z._realloc;var Sa=l._i64Add=Z._i64Add; +l._bpg_decoder_open=Z._bpg_decoder_open;var Qa=l._bitshift64Ashr=Z._bitshift64Ashr,Ta=l._strlen=Z._strlen;l._bpg_decoder_close=Z._bpg_decoder_close;var Ua=l._memset=Z._memset,ua=l._malloc=Z._malloc,Ya=l._memcpy=Z._memcpy;l._bpg_decoder_get_line=Z._bpg_decoder_get_line;l._bpg_decoder_get_info=Z._bpg_decoder_get_info;var Pa=l._llvm_bswap_i32=Z._llvm_bswap_i32,Va=l._bitshift64Shl=Z._bitshift64Shl;l.runPostSets=Z.runPostSets;l.dynCall_iiii=Z.dynCall_iiii;l.dynCall_viiiii=Z.dynCall_viiiii; +l.dynCall_vi=Z.dynCall_vi;l.dynCall_vii=Z.dynCall_vii;l.dynCall_iiiiiii=Z.dynCall_iiiiiii;l.dynCall_viiiiiiiiiiii=Z.dynCall_viiiiiiiiiiii;l.dynCall_ii=Z.dynCall_ii;l.dynCall_viii=Z.dynCall_viii;l.dynCall_viiiiiiiii=Z.dynCall_viiiiiiiii;l.dynCall_iiiii=Z.dynCall_iiiii;l.dynCall_viiiiii=Z.dynCall_viiiiii;l.dynCall_iii=Z.dynCall_iii;l.dynCall_iiiiii=Z.dynCall_iiiiii;l.dynCall_viiiiiii=Z.dynCall_viiiiiii;z.d=Z.stackAlloc;z.m=Z.stackSave;z.q=Z.stackRestore;z.M=Z.setTempRet0;z.J=Z.getTempRet0; +if(X)if("function"===typeof l.locateFile?X=l.locateFile(X):l.memoryInitializerPrefixURL&&(X=l.memoryInitializerPrefixURL+X),u||w){var ab=l.readBinary(X);P.set(ab,Q)}else Ma(),Browser.V(X,function(a){P.set(a,Q);Na()},function(){b("could not load memory initializer "+X)});function ea(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}ea.prototype=Error();var $=k,W=function bb(){!l.calledRun&&cb&&db();l.calledRun||(W=bb)}; +function db(){function a(){if(!l.calledRun&&(l.calledRun=j,!G)){Ha||(Ha=j,T(Da));T(Ea);v&&$!==k&&l.a("pre-main prep time: "+(Date.now()-$)+" ms");if(l.postRun)for("function"==typeof l.postRun&&(l.postRun=[l.postRun]);l.postRun.length;)Ja(l.postRun.shift());T(Ga)}}$===k&&($=Date.now());if(!(0c.A(f,a,a.length))console.log("could not decode image");else{i=c.p(36);c.B(f,i);a=l.HEAPU32;g=a[i>>2];a=a[i+4>>2];c.n(i);c.F(f,1);p=c.p(4*g);i=c.H.createImageData(g,a);D=i.data;m=0;r=l.HEAPU8;g*=4;for(n=0;n + + + + + +

BPG Decoding Demo

+IMG tag:
+ +

+Dynamic loading in a canvas:
+ + + + diff --git a/html/lena512color.bpg b/html/lena512color.bpg new file mode 100644 index 0000000000000000000000000000000000000000..54c4305a55b0babe896a4131a7026ffd741b5a9f GIT binary patch literal 15148 zcmZ6# zmF1g_a`v8ob99Q^4nq}Tv^KIFC%|40ubj~_>>TQpI;P}I$JFzZ-})#=uw`%EXBIge#xQjY<~GW)`tDnShI55{xrn}>T5gRR_8UoSDN#0 zzs^g|oc77W4nAMc@=SUh^u_92=HG@BcG~y17q)7yv+(t4_3pfT_nyi>foHS%i!`eK zMtDr~>n#YJwBlG>Qt0Khvbuw3=6PrGPhxqQxiJ0Zsf$;{I8|*Od^e?@YShoaA-q=O zQIomZPensp;hY^4F7s^VTd%O@EYHd%`DJIHM##D^Guabk{e)xttI3Nv%GXGintnc+ ze?ffzyBTQ-#Yf*A-^%jxX4RFQZ)NM39SQli#LT&Qk5r!My+x@l&d!^jm1%Gv{4Lw1 zzvnyC^#YINiFK9F_w4=s)lIH6!jq|TqKVO2t}n*&Z@;d0tIz1nKb{of-f{2WuMU&` zg55VNT{rOta2P*NS=cgB=aT04mG_D#%f9W6nl@W@>WW1M%4_U`OB=%j3J-BDKi=D* zb%~AtoK*dpX7`%(#(7-#_}Py?yAc{L_aJmp=(hdW*ek==PCW8XzUd{)-IQBSm%n?r z=}!+^mi5Bt{&qX@LXACHKflNQw77Or-!dh+ZMiq+(gJ4JM)&In4zxUK{?}^UGB1cX85 zx#l|vezu5^5-2x%efjL>C;Bm2N4&NjwU%z(9W+PTP&22`dSUFe?~m(F9-7k~^Uqes zhRdqZ>596+qv_mtMV2#)I(HhIUDR4|a+!av-|nM-doO;S(rVG&<`WY>$E532{gigD zV8UDXlxkUCfTlIn%{5x>e;Q8FF3h8 z=Su8MN&WC6^W6Gpt$68o;PB6im_OZt6RJbnA`Z;C`u?v&t9#(#TioJfrJeHy(#%9hsWVT(_KOthE2<^ZCLf^-9(24hc=KzuE}6>Zw1IySFfs z_euKKFE2Fa>iuc?`QFdm#_2NCO(*A<;YYcXTDDv@UhwkG;VQ-i>+c+j-T0fr@_zB-VxEq@{2>Oj z^B;!pEaAFW%Z~mlh?P|pZ+oxec1etjb(=}N zrD6=fCi7~w)12@8?@E^BEZyq)wp{O(n_z_cy@J(i59I1Bvy-y@c4p00y}Grzyx)}1 zC~$t-`}O{Y{m*yInR~9r`UKZQUhyq#)vmYlzWE$i%i~QuCYdhzPS)_%AD?G(iz_4_ zODy<#^|W1@Ra#`x&RLf-er5Pf|G3~yYnc2E0lv!rJN_?h*G#_DH~;HT*UUSPlQ)>0 zxFS@!Ff2S=jW6$Iz4tf2&$=_FyOc5Rt?sF*5WmxR*CM;9o^hJ-wo4Up3|(6lSJkvm zSbk+!!PElczXIF5z#V{)SyTe8-JwzYwk? zu61&zYkr-3-(6oeY31?rX)}ZRlqX*BzS*>Y>#cH60iDx_GIdqo?O;Cgr^;IS&abnq zTkme>$nUzUy1o5u?ullL##qHr@O%7!eUA4Y@%Nkb`r(F}aCdni}v0GT;T(_mk9&|dAI=OJCtj%8k<+C(|xOk5*kDC7@%6ZxyYYitw&ddCZ z9$)cr`(}20Z^`G4>T>^P?Af{F$LnR$s?%-Cb$UDBnRa*|Yk!`7#Hyfd)x7IU3H`?} zU+U|e8hh5R?n3Fanetf!jIPiRCAY|c^HTv5KcYB4dd*G=}?7I~F@*UB$UsmFMwSt2GKU~OJi zcP3L?G_hjM0q>Y<=}M7B*|O8EPw&{)=U#m7=JK1K%vZWfcpus}d+dyx+SK;-*{$ZI z$r5rq-uuJ_9$U9BEy(bvP`&8f#ObG|r2c-GurlAIw}FrEr$XVn9YrZ7Qz8zp{b1_$ zXN8Zs->;Nwx4w9Hr*Q{rW(O{GIh`rkn4%@~u)yv{oI%AG;~B0tYo~b4+<(Pm+KeBL zf7Pv~gkQQX<>3E*>LUhw=en;kcl)B7vhwpo@?KU1vxe%&Y_qs=D%SD|f5Y~R7ygDk z)>yLP?*qFnhtBS+*zuzBo~N!4v)~)S+LJNISY01@CT_d+CEVkSL(f1b_GcTJ%G@;BL2e5`N!=B&}bV(-9yUVi!A zuz$U)tc~k#pHi5m_1XOSE@h?2P1%QBSzm@}b+7%$`6YzeeD7@bw#3a{|M&UIyg%m^ zWII`A+TMazhjUGNeLrHSEBYQOis;xYH+T0%woT&yXA4I* zewyNK0G$zTdZ^15dW`ap&f2-{$L`x&FQNYleC0yw_XuU%i*{HZzKk31zq=Hh1;= zcdVbXE{W_FTC;f5nMXO2WEzW5h*JKMn^n6ssboX-owHFCfZ~4}B z%`-prI(yxPaE@637jv93~yqAzCYX)RhlclIwH$r#7~ z*AB5Nhm~`+9SQzg(0#n`Yfk9dz!$6ADo+%Mo~^n(p+?hNXW5r4+^lUE^$wISc&)L= zH=N~|_V2U5?>};7`keP7*5kID>s1j6lj#Pzyo=1UvcJo{_E@m^u8)n}EqqCK0{`Fow%@nY};*v z=3j=^la(4nY$yMnbcR>?0?YaZVlm~%lnP2OX}zDLaxUdy(DrF@pR&$uI3j*|{YuZk zSGOWguA0x8yDvN~G*Fx~TW8rz(cKZBR@R!`&7I((5o^PCW9|IcH#%&NPLou7%j07| z+d`_u)C7WnuBHu^nj()Xv{oZXURIek60m9kcAI)9iH(>;8r5uacMNT{#i<7cSOoMFG`d8oa`y(>(|>*cZ!n(ydKxa_|AUuMde zH`c=Md!)|T3G?Tu9d?|endz0i_FSwY>znDH`}gdx>VaM zx7*h-($U@^a_>e)CD-8l&Px}p$v*M-*PM6Dh1u?XWG*jw z;;PI_mX4eo=Y{9^i-whaDmrz-CSldN!iOI%7mCbyQ2Mo{a*DFVujWsx*19+C%Rgn7 zPpgSOeDh1C=riqW$co6jIyqMYE@?(G0-ugDz9JP-Z`+WCG*&J!HfK$qe zTdn@Cym4D>EBAq(U00VMskJYC-0XWU*5-0WpIW(~*ZFsSj1wO%F75~w?qg4Se<|YA zPlY|#%oCoSshA!ep5J+1>vq+OCNrm&TU-AvV_LU%#)8+UHtwDs`n%texBO)8=^yi! zKIidk)7fHG7V}b?G3?c}g4f@&BD;>V@@(&S@5=gdc#BZMalt!I-^12F-!i*BdhTvl z>*f?W>z1&8WtIgIcW2qWEh#nB+g|^tw^?RkYP6QivhsqZTdn`hcr#nCvcsT22W66qF64woXR9wFj+&1w}(*!+p3+JCRlSQvby38_k3!h&bvFDol z;{%BjGr!(^5~Y$jX+lPC=hQnL*O}oI$rE$J=7ewj*;nCJ;=FkBdXHaRzU(u0txRlq zrhKLKTbJ~$t`!-IyAB_!?X5U^{N2_*&x3b1xaho!>EL?rAFsx`wDzI*#!+nS^^m)MFlWX?2p2BnJx9N!f++xXL~?!fzc#`hABuME3zwQDKUqsYM0 zlj+xvzgd6o@%f;z2To@7(i6naUTFJQS-{1(qRZ&jJ28)i8~$;n%Z@J0&~hgI05KmE5(I_NmzUlIz`4j%LGmyfbHu+N??X zTp}Qztn>AQhTDap%$-Y1b>+8k@5(l~l5YC`8+k3vx~sVK$=BY~ z-WHK}E(six{}kyxXU-cf&idl=n8u=uwsPw;zb(&V*KwTU_(#{^;DWDH|Ns7`{a|;? zyh%%Q4ty+kXXXF)>T)e-*ZHe!p8fu><=(Mplw4msanb zu~hi*?-S7}2E5fF8}6R^cJPRTy`jd(Fsr$%`wz#RGb&yE%;4j*iT9+B|9a&aqF7M= z)BD@Pr|~yFlYPkU8<)ZKl*o%^0D!*7MA+;8VzwC&ROG(A&&qxHqZZPLo0Bn3_iPJJBpSmc~) zS$*T@FD&zKefz4&6V`aMbm`o*`sP`&Z!Wmrl05UQe(UU(6B;j<)YI zw}kornO$40UsT0rRNn86biJoiTo}8qe4d^A^?wvGm!YljEbvM@RfA`0$#CG~4wV4s?@~rf_Tp05+qpsFDST-0(AIf-U);$B=q$yXQ*zSqdlRnpxAt=7haMe=7Fh<5i z*G1jdD;z>Yr_bweUd(soPji0r>wa1B-pw8Jxh#y%EVX)YsOi~*370v~e2KI^*zNw| zwy|Z)PS)pTtSVBgPjyGASQh>`nzHls#MpiIU)H!UUvFe$;Fb_y8t_F}=~HJ}S6$@W z>KRXKretjwT4=bmtM;)0-+kuf&JT0vmz+D;rSm?)LOA98($L$!`~|7zx0|2aBv;&u zI4Sg;!NMo0d`#P()+#p~WD^&#xuJdGLx$T9 z=LXisIg64%t$J?#Lw8x$`c2;VpFY>JJD9X>V&zE(mGh@p*UIm*T=4P3<<<+6e|^hz zefpzbis`n&sZaAN6@9{2&o1HKbl)v3GU)uqOJ|+dMnzjM@ZtUW?B$;sbC@Iq9v>{$ z?Avd{6zf*U`(FA_fZ5$};q!-9tO{Reyrg>fLhDTVOum=@D`TI}{+cLs+Ii6*Rf{FR zd>f2hCpf5hB!=r=d#kK&`@1S{im~_tzh5s4s}1~jE#gvfP?Ir;o41i!#N$?{a>Mei z0UG&VPp_W;d|%@W6_&sEAAc=w?{S>=eBMXzi}AK|Z+^QuWv-vWTKSL}H!8e@#JCvx zLi(H6e0Fyid7x1>f9L5n_ERD+eXremIq3G0Eo=T*#hi1lVC^~HY2kUdaZcFfrTXnE z2b`BY4_3X$c)W%6z2MvHk24M#dM`0_TG79UeWMpo=-;!O+X7t{|9$B>;j6OJ%m9}a zpA95`bRMkbbukF^PFTdtH{;soMS`XYA=(U4jL`zUa*nHPwRl9neVO_CP(h53`4(#p z?f)BWKF`ejy5IyG--dHv-mEcF`gm~l^;^n+r~FuGn14z$=FCpVLgwnEfVY-;svQch z+8z=T_ZX*a{j?>9ectx=?OXWv_P&kUsDJ(7-LTVZHcx-f#u06#`Dd2)OHJO!+0Fb{ zM68t0v}Zj~5W6iN?)E5bmBZbn-kq=WgL&3IuFbKyI5pSFQ{#ALb}9dR`=cUe&r-j{ zwsme)z3Q{-)Ao##CWo3?58s%VzIgSmK|5~e@r<L?WPW{qOw4L+B|BZ{8 zyisD?En(Bw@74+LJaT1=%nQ+ez1u3j@|Ro|Pb%)ZYrnsg!+$CZ^S>=}uh_n{)K>l8 zCLdyV>9ES?06X)ZeRG=@%(%Mg$XbEFZ{xn?MZ6E6@hA7w?zcO1)H)uXJG<$ks#?FZ zaYD@h-@G+qiAO@7G_GY@>%nd%*l>EJI&Q(SM(R205SGv{h4=UVb+qb?Y!Tejcu!}zx+Qdgo)fc+h)0chxC-R4arw>ABZ)l@*e5y zl`(33)pEvjQ15TnrUj;F7Sf>tDj|ho2^1 zoqfAfEYEGhp}#+#mY1aavKFkmd~L5y#hXLg2HO=Rw?^`BR$FR&LsDdy(u>_Hmw=arWK69GJwmFMj_QZC~kz+H<`h8|u zPnPoD`RPsjk_4jcj_atdm{!jD?Tf|f;Dtg7P z>cyvLCMvpbPo2asc=dSI_NNmc$`*ZVc1*mIdT+CcuIbEgifnue8(W`fa89_q=SM_{8pb(i56a3}Z}=f^$h=SaXy1oZ`uVH@pT&5zo^5@+v%Wqpb5g5>t@g6JSN#1a zu{B)~?z{K)@cYmAlegLRZ|X{%-j4@nz#uTbFmbcfLLd z|Et1s^7Xz)(I?cFn5rkSclIs1Jg+!TuyxkPBathC+Hcei8{_j>%;#2$S#1qugy}s8;`IXg4m3+r=zvE0UxAg^Mp5}iI zD&x46EVyFdgw9z)GwxZQvsoM~aZrNoB->GUwcV3m{$IC~B`WbtyqU+s&M#VvTGz2g zO_^%PxBp2@+1b6fD(*cCpAywv@mKTh^6!4UQ&zf_d=fj^xUJ<*qn^=k#bYbK&8tl= zj@|C@>OjtquF!T3LDzZZ{b%^gCiF{iNC}i!<-bmxl`g2EG)-P1bKhUDhKVOuUk#N| z`*wMz)Vvz?WWV0?>U^IKZj0Py_^;!2()L>8PVHT1L|2Avw&2-*VsnB(clbYF%g#i> zFJ+k}&-&%o?L1QSx6YxODTFq-r6v zoK--{mcI6~dErcE6B!>EE=sHqyNP!s)+;-5*%vOT#0zzic~D!m_cW`q6xw zxwgN>W3A>CIcGK3HGjGDt2<#@ji2t9XXj48+jBHt-JK&lP*h0r*~2hJ&RAvdhKW~i zh`JwYfAwc_?a|oKSbz)0=+BGSNqj+$}PXxOyQ z+>;*GA0yW)Q~9V-6gTeWD# z{XHp3g^v~XJu7iKe7HU<)j#0Pk!>?uJk2-c=xSa)pd)#&ry}I-p-ZP#b9txv3zi)C z^u;4!F_&3Izg}j}%br5}p9`f7xAo-wpX?yH#cu9-oBtXq%OZpSp1e5up-yqlR%M69 zi$1liUGY-6fBi#^h6j;l!qsb+E-SOUr>j&hkhPWA4U7>W^H<*v2#=Cfmxnkm!6i}vOLMc`0~S=nb$cL?M|iz z_4NiWOS`nEqjI1B`lL-)ls|8Hq*|S*c3xqU6%g{YB6WmQrLLE#>C5i zg{df*^mG%kfpS*Kn?xr2hQ@mDL zob^sQyVUrZ7Ms;}fuD;w*O@vN9?88vZNb8MH(sxuduEm(|MuN?E(oqZyLf?HjmyXH z*>6O*y)L=(rnkuR^`9e;xx-@vJnwej?wTwAd5_!%iR{cZTUNcDe_!;@n;L=7&v_Se z-oJO1MQQ3xtBpGptB!oSaLO;Dd+#nia+!iKK+%yuzc|~exE(r2{-e08Q+=m zCH~Ml-zSe>xFpFI)MOhjw}_~jx?sub_QI!}RgaYI{8OqoO?{A`eLbq8{8;0wWxaco zo@BL#zkGMy=&QV-xylxuDHkmc@wwH>y%+tL5*@cWBHuY#Hu>!9yDUzt|JX8LKHuo0 zb32v)I_Ig=(Np(-pDVjrh^u7LoIUeqO=?lxF1}nnd_%{t1$$oR$$oYCb>@xpUMq$( zTt64j-?hZ0Y3lZd)p^WeZ|hEed$<1Bdh5CC+~qod+ij}++iE8FGGo!1yi1y%?swIl z^yL#LPd4+`RlB;tg@x5&)8VX*y{q;uUGajc&G7Jg;hJ4{?NVnS7B`JbdpFCy?P#xz zwz)!wi@^?`jHd8QEX$53giXI7^!vT2&`p&WVQLXgZ%)OOuHkv|YS+BrMj_~pb&Hgh87;??i8B)*s;7x_s~@TxBJZ4UwohkWzzdnq zd$T#!ZmRyxO_)^q_eDbZO*N)#`%`#U?0Ryj`bpU}rM8EwFYlGQHrJ+QO`1`bD4WD2 zo_SBhzs&lm;8pdiYS$h2fKPK|Qk&j9_#dRpdTWR5w^K8+7~Bntv{p*AE?AqPeCfxP z`>z6mWAZw6=Ff1NKl@7bqzPXe{X#d11unfYeSNyo5(`$2vl@%4PiuepVz&LzUggK^ zJn{wB_0vCX6fT$Fd0uSOw9W4FKc@Y*fAo9n{Rb;6=XDrO&3p5YH?c0(?%2+dJ9k9> zo{T-a{BHZRtgQ-Ol9481$V4`d|L0O6y#?2QGbB8sh)O*cdW!j;hbdGHBDSeUzh%xzL~9XRYmTly!+hDA3f*Y*IIYr@=eCr z1t#YXWW^OR9DX?MRoNA5mBU6%I%h>r$plTS3RrTtrRvDmUnw8Xx%f`G(e%^ndsyQ8 z_dKdCZ^eSX?m2(v!IR6=U1u!y)|5Nxel)>rYHYuJ?amvH1|^j*cHY{o!+X{6t^CDp zD^E0QiUi!ac&RX3|Lu-;>5|Hv6q{Yqxq%g|aXaj)>|dYF6g;)wUO-CFAp40I_pG-^ znj|EG9)3@`P#Yq)yR}f@w#;ItMJ`bXCi?dsQ9A7G026)P6yMp45TjMuO7em0r+{x-AWija+$ z_on=hIs2T!sw-|=g6r&Ud#vx&=cma&YA`%*=sDqz%+bw<)h8@!Wfv+|@SXKo@?2V* z#+#Dg7JeO8pC>*}w5+;*TrBa*t_AtsR`WERZDo_Pw4z?N_8#N6`dA(|Z^Pg3?yu5U z3jLG#@!i4hWI)dOh#OkpLey2u=N@|XNK#@=j9W}%#k-hmnqe{MI?2_Bs>R{B5$XOY?*f|2lnTj*{3;1NQus6TVx0de>fy@j6m1AfCsk^z+7jkzJZwT$i2G70PvpJh%C2InzZ~AIbRn26ule zx|;jvs=trBuK6gnKz_roMWuFXU-!S{b5fSPyw6ME`>zFjoQ*lU+udvb9*N~*d;e@- zsiNG}(pc}Ufp$l%9lgH&*J=s2Zu&W&DIxmMrL>yDn%SQn`kG=@B>xDgT$__5y~4#a~kOKJnT$tkQpVi8DvIZF82x#49Zq{hoZT)6BlSB=FTLe~t8_Sou>Ecy~;5 zHugzM?JaCw8YCTQ^U2_Z)&v{NpWj91ELEs8jXJY`jm7lz7_p!nL+itGuQx^}3cr}g z>}iwqvMOj>P?zYZ_5KWJ=RLFdq5u6?$?EwxbvIY#r)c(@gwAQ+xu4ya!?s=X5@)O9 z%eNP=T`QaB{5#t|_4D1ov%{F{Wlecz=gF>{w0}<6w6{g=Y;$_N4o-X@Y(JrRPPX?| z4U3t(tS|I!?F?Udp=gt=;__(oH#^RJto-TvVe)C-pU;gpF1saZ@^_m0uG>5+&5Qka zPwU&C*73(veL~gmSu+nB=Y;O4|5aoYzR|-;V3l2R`_u@BRf?CCH{3s45!=GMLq=KV zpU>+iYu`=!$!U@-Ew#3ijDhz`_nkZ-GD(`{hA z`agN|eojkU)RFda!UnICl`A?U^H)r^%1=H1#OV)%g_1DmrR`TkO*ZuLe#>GCc^_8N z+rpdUth$2x{w>iDNe-pudG^OniZV9tubywy6qiu@ttFHt;*s)X>&LE=&sLhMXUysm zn|Hoe;p&I?EoqF3cbOZbBAr^!yl}m!FE(R^Uv#@$Rl1$$oIM>cl8c$Q8nR22Pg>g^ zS=M33I>qI&Z`i$TTZuF3|1%m{Z_jHeo6yFXQa#alnqcumAqN@eg*R+Fzm#uLt1XpJ zROn#W+xq=Mvt+aIA?d_mZst!rT%GD&A3cdI6Z(-=uHPo{eS)v+bt~;@MO&{khKA1$ zQ{a}ck5s=WJ9BlB-HxSuyEQ$UE-Du@itsFMUw!m;VrQ1EUAvX^N@=YH=NAXBx%bs_ z>S~TlDq>A9gJitSZeD2lbn?yFw?CAB2=u8hd21gReEq|{gIR7-ea43rvpbjRx$trX z%|E&?Q|?rGrQG!E&Qs4lp2^kpE>Bu6{s+%Lk^d2YUbUCz*S6d}#d{`?+sDpK)}Ci~jfT zhS@K6P7z&cZ@ub;ro7<6ab$e9c?8O{sb2Kk@yZw091X z(@MFE^=cLOgx>mDnEgh7>WcgPtgbWSdpB!@E__$>X;-k0Wnk5Q*~33{L>34c#!im! zI`6V0|E=DZR_li!gd!*WKfv*LLR`_UDzlfzf38TKY%NrNM${{4kKn=M2RCIc-LvLt zxsVb&(=zj;Me8ja_HA+6qf_`kXUVfi79O$^TYNtXJd(3*;{W>39Zfd3D~XQ3FSRr}y$SvE zqG{b}JrnC0y7ikDM&3+)v}V&sx81dsCj?%a`S{+IyH<31L1*#(lk-~lFJt63Gm%-b zTE^aKO`%__Q1{b=^6ApbzMX7&)Ae-}{duP>n#edU<>Z~qZ+<9yD@q%C?21^}@cK>h z+e>d>Xh(=WzOm%J+m986mT|LQ`pasZI%J|=uP?Sc=1^t1NH60ARq>N=9(y->xIUD; zd}iIvA4|%=-`d?Fp1nRoSmTp{)eqT=Db-h<9L(qDYHdl7z4W`H=wj*Oy%VbsC@Z_x z9JPvCb8YcX{w1{&9pA0b+-()8z;VAjLT>&yVzm2(Y=22I}HUlrU7t*^Ny#K6wu{hMr zneSxul=mXbx$`Ib?>lyPLH6PFJuBUge-RRNY`GD1F8tts+hf_SVJq@QALrk@@Myu7 z&<6>{?^^U*J!JE8jjfzNm$xs^<~O{Q`aS-!*iN_G(cE2po8nir?3pm{x}gEFftGSu^FVx_X-O3`TsJB`57~XbhaGVyyjy6=WS7?tIFnhnST*?m;Wi^ zXx@=pHLK~D1>3~k2Ze>>f7CPf$IV_+di}Ne%4-u7FV4HdIq9TptJw7xU!NCz`-NVx zoJxImA*Q+E*4G`&xqaVl@RYw^sBpSC3QIn=z|GRGGt-9SR6H{!h*gP{r z&sK0d={an>v(f7Pgv2!_dT;OZR~}A@U1-bj(a4nRv6uFu?75054{JA8yx#PG-)||| zL=E1z%C8syp0XrEc!lF3pV?sN!C$91`cdQ|v79;kn?!S0Zn}WIu2TuHwBi*-}c!eet`QjSnWAn{_tRSKRV^=ic+z z1Ein!Jo;UHws*+|yA|E-6DNN47EI({lkie!0vF51biY^UXQanIZSc~Kz5Da`UaNWA zy1u9^y>xEs<@5H&*WNle9L(P9=<%fBhUvSlJDeJIKR*=e_X@uHMs8c17L>}2?a zCYGPssrD_j@Z?v8BjwG%*vz+GN}teQoUX3gy2w<2VXl4RzMBor-$j^w53Mq5DdhACEs(=BpYeq8dJywAdE`Q6QGZdYYaoo`E; zxKYvInX9f4Q?bV~(X_vIDZ6$)KeadfTy<6{U(lvMv#si{&NF+#ZNBFJ^xaP{e^tD8 zcGs@b2Io&6hG#AZy+o7ujfJQEHG3VyqJ_`tz=w@ORQ)Gr?hRms`>Qm3h! z*=oOJTj7a|MKgH*g-}kDzI<9Rx1;+Rp4Iu~k9Jvb@t&3L zI-1az*rL3?w%1dupj`D!{kzL8Y%2b3(`V;?)A%C4DbAunERp5yiB~1R)be$F&b$+S z*RrAQmGF%vEz;Xh3Itr0VW?Qg8FBkcoCXVP>p}7P%qj*q)S{(CTx*v9J8Wd_x!@p& zdalF7FTb^o<>Er$^9G21ySHiLp>^+rHD1{BM!i0Bu21{xh5vC~mXpi66r1;N$}qL| zm(Q5JQhogbmW$T|f2ns{m%MIKTTtqMa%1c3%gs7=Q4!K=nROdkoTa_Rb&hGB-Ya7J zV4q}RbzYwP#=fp(f$K8CQ?ylTb!!$fl~sQAL}+*Ta6X&xhc)ToeE*ks#0z_Ly8W1$ z@12mDxkyk#OeF5B!#tVpRA!g=O_L`~UAW?eUP2C2#6rzKetp-EpPi}__3@gs-)w`p z@INYSYPK~i{;XHuC3BZ;m-y;;zF)UbPSurBV*POC0g_G z)z7w<4(55J-@mzKJHxw@q(!a=cFn$$wufbYr(uuvzsp4)Vn4Y5tobwblbO(suPKFf zzjNGT6jiFuRK0NHyY))8=7Fuyy>q+gDN4S5X8CE=tfU_Yblk0g#NIjnGW-adcMV-o2S z%~?n12REg!y(_yFP~$!SNa%D|!+r7Buf{BY`dH=4g?)>3j-0&oJDbTn(yzy3@=49) z^!g4qEiMJS!)xuYpbd;#H;M z?iJ_0PPdABA@ODE*N>m1l^^)-UKrLB{@ZV(@K*O{2OeAR&eB;K-r%*{`lguOiLLJ< zW~eOQpu=9UeV6TK!zIcdpZM07mG97b*Qv4Y_9JD!Hw^O@HT5i8eLnl|mK(cNd4!!Ouv3{iP;y!}~jjAMGI-Y=e|7v417?vC|slks|!IBAvfp|kVD zwYq*EywJMRHTO}I%_f^9<@u*PesH)f+G%c>=kw>^`reF)^Jh6)#OqBa+wmVOxw7ie zSJx&+Gm(!5M>Ict^na1Lo_|W>>eZ58b~n%Yq!=_+C9HeSUb(NA9UZ3>^rYrkfA^aC z#qj)dBN3)+VaEjxoR4d!$5dtN9R0s+OTAI)SGA@658XpOM5f5i6lxC%X}@0Ka(3xL zy_@#81FD*~JdSDo^T{S)sjtivX7N6E|3BvQYtKfnIZ@#xZnxPaHp}9W&^`a%l3$em z<~~+AWni|2`-{Ma{tepVVaYY#Atv9h*I)En{NZEa`dNxW&u2dP_~GNt#S$B=H}o!& zd9LvG_>^wriIwpWLR9&5-+d4ejV1omuMQ+7~EE30R@$M^qQ#}5?W zX0tl9(#i5&YsTXkb-O#Ik7T5_D@5`oZk@WNZ*|aL9aYZmu$-4!2UGv6%xcO0r_U~M zHGgX0qBK^OV`1vAbezhh=cUMQF6ofwyvX8lqS!R!mfP0zCSPYvkEILL=&Ty zy~dWj6UQohF7-W)j5fB;-}$GoX0`iufxE9XZdLbu&ktEG(|=^|Y+*hY?q&YWM*CQg z_^zB?@Fk&gVbYw5hi9EW6#vutY4zjBLcE;!H@*51{_(!KcmKR+Mg@OdEWJ*fKh1UW zJrwx!qOHZk!?PylFWoQWV|e0HrPXWM=Vk3jtev!e-O7?@fBeRXW9Fvwt&cu;&*T2M zIqGkMLw)qeWtw(YvkkRvcBSuIqUazYCijJ)Pe>cvW6?WmDZf=MJlgN*k zKOb_7TvTur`4d)mUhDm;(?T0GFE2L{ustt1=|{+_&8uH5se7QfeeKTL{ZCCz*)`*t zC(1jXQ+Jfh-!v=sV2*yu3&v;tkN!3KDt|I%W}UH<=bdzI#?+9{9SaPkj(p#3`fX!v zvXHN#W8|TkD>j90ad+9#oyx29X4m@!mgx(wDV|79&blUGIfr-kykMEsvz_hkqCZ(G zcRg5J_O;r_w$Rz?Zt@4`#{P(~|J-QYueo|pop31O7xWcSYGj-#vrQB1)DksPv zc&f^Ks`Ykw+KFYpw_Qp}~D6(<+lz)}Lm4e8W0XLA&@!=#eW&BW@ZU z2}(O~U;_UHk%qtGPx+kB&%bEBDlU6ZSEk(h^WTc+++AUuZ2o(KksFW3o9UvT{+c#t ztSM}`J|VYj_G0}7wSpo4Z+$+x)Z_cX1INDUY1uvJS6{2W?K8V_Ki7v&%m zE%y0J({KIaUU@NF|0>rHqh#iq_G{&*Hr1>x*|o^qeaqSVv%WIjtMt8W)iA~4?jEy^ z_T|#+S95M`%nFRzANM-_P>SwH&cg>k?Gej7A7y0ad#>kc+QNqLnkOk*PkFu@I5H^k z9+|kCb)BrrlABt_$NR)rh_}wZxiaYVtQ~(hdd2w}8D25H5cq0~=E9s~QvY3_b6?xD zl>3+69PWap!8tGZYEv&eJI#uc&h%N5)@S`%JkPb7&0@ud^Vx^a-#(Y49Cc3XFIPnI zwpXvp9CNJf-RA184?N{3JH@V{Gv_aP*K@Viyg#GZ zX|d?)suf;|(KYJ(mG8x_zP9Z}@{|&v%?iuhe;o+t?3t~$IV#P}<5}<5)mLu(x-9Fu zYMOfsC$pHy0kNx-{#<9MS{>9r(V*X_*u*5{j`g2aD$)*j>o4$}@5qZ(-h1EQv|OR> z`S0uE<$o6Z^Yb`&;FZcX` +#include +#include +#include +#include +#include "TLibCommon/TComRom.h" +#include "TAppEncCfg.h" +#include "program_options_lite.h" +#include "TLibEncoder/TEncRateCtrl.h" +#ifdef WIN32 +#define strdup _strdup +#endif + +#define MACRO_TO_STRING_HELPER(val) #val +#define MACRO_TO_STRING(val) MACRO_TO_STRING_HELPER(val) + +using namespace std; +namespace po = df::program_options_lite; + + + +enum ExtendedProfileName // this is used for determining profile strings, where multiple profiles map to a single profile idc with various constraint flag combinations +{ + NONE = 0, + MAIN = 1, + MAIN10 = 2, + MAINSTILLPICTURE = 3, + MAINREXT = 4, + HIGHTHROUGHPUTREXT = 5, // Placeholder profile for development + // The following are RExt profiles, which would map to the MAINREXT profile idc. + // The enumeration indicates the bit-depth constraint in the bottom 2 digits + // the chroma format in the next digit + // the intra constraint in the top digit + MONOCHROME_8 = 1008, + MONOCHROME_12 = 1012, + MONOCHROME_16 = 1016, + MAIN_12 = 1112, + MAIN_422_10 = 1210, + MAIN_422_12 = 1212, + MAIN_444 = 1308, + MAIN_444_10 = 1310, + MAIN_444_12 = 1312, + MAIN_444_16 = 1316, // non-standard profile definition, used for development purposes + MAIN_INTRA = 2108, + MAIN_10_INTRA = 2110, + MAIN_12_INTRA = 2112, + MAIN_422_10_INTRA = 2210, + MAIN_422_12_INTRA = 2212, + MAIN_444_INTRA = 2308, + MAIN_444_10_INTRA = 2310, + MAIN_444_12_INTRA = 2312, + MAIN_444_16_INTRA = 2316 +}; + + +//! \ingroup TAppEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / initialization / destroy +// ==================================================================================================================== + +TAppEncCfg::TAppEncCfg() +: m_pchInputFile() +, m_pchBitstreamFile() +, m_pchReconFile() +, m_inputColourSpaceConvert(IPCOLOURSPACE_UNCHANGED) +, m_snrInternalColourSpace(false) +, m_outputInternalColourSpace(false) +, m_pchdQPFile() +, m_scalingListFile() +{ + m_aidQP = NULL; + m_startOfCodedInterval = NULL; + m_codedPivotValue = NULL; + m_targetPivotValue = NULL; +} + +TAppEncCfg::~TAppEncCfg() +{ + if ( m_aidQP ) + { + delete[] m_aidQP; + } + if ( m_startOfCodedInterval ) + { + delete[] m_startOfCodedInterval; + m_startOfCodedInterval = NULL; + } + if ( m_codedPivotValue ) + { + delete[] m_codedPivotValue; + m_codedPivotValue = NULL; + } + if ( m_targetPivotValue ) + { + delete[] m_targetPivotValue; + m_targetPivotValue = NULL; + } + + free(m_pchInputFile); + free(m_pchBitstreamFile); + free(m_pchReconFile); + free(m_pchdQPFile); + free(m_scalingListFile); +} + +Void TAppEncCfg::create() +{ +} + +Void TAppEncCfg::destroy() +{ +} + +std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry) //input +{ + in>>entry.m_sliceType; + in>>entry.m_POC; + in>>entry.m_QPOffset; + in>>entry.m_QPFactor; + in>>entry.m_tcOffsetDiv2; + in>>entry.m_betaOffsetDiv2; + in>>entry.m_temporalId; + in>>entry.m_numRefPicsActive; + in>>entry.m_numRefPics; + for ( Int i = 0; i < entry.m_numRefPics; i++ ) + { + in>>entry.m_referencePics[i]; + } + in>>entry.m_interRPSPrediction; +#if AUTO_INTER_RPS + if (entry.m_interRPSPrediction==1) + { + in>>entry.m_deltaRPS; + in>>entry.m_numRefIdc; + for ( Int i = 0; i < entry.m_numRefIdc; i++ ) + { + in>>entry.m_refIdc[i]; + } + } + else if (entry.m_interRPSPrediction==2) + { + in>>entry.m_deltaRPS; + } +#else + if (entry.m_interRPSPrediction) + { + in>>entry.m_deltaRPS; + in>>entry.m_numRefIdc; + for ( Int i = 0; i < entry.m_numRefIdc; i++ ) + { + in>>entry.m_refIdc[i]; + } + } +#endif + return in; +} + +Bool confirmPara(Bool bflag, const Char* message); + +static inline ChromaFormat numberToChromaFormat(const Int val) +{ + switch (val) + { + case 400: return CHROMA_400; break; + case 420: return CHROMA_420; break; + case 422: return CHROMA_422; break; + case 444: return CHROMA_444; break; + default: return NUM_CHROMA_FORMAT; + } +} + +static const struct MapStrToProfile +{ + const Char* str; + Profile::Name value; +} +strToProfile[] = +{ + {"none", Profile::NONE }, + {"main", Profile::MAIN }, + {"main10", Profile::MAIN10 }, + {"main-still-picture", Profile::MAINSTILLPICTURE }, + {"main-RExt", Profile::MAINREXT }, + {"high-throughput-RExt", Profile::HIGHTHROUGHPUTREXT } +}; + +static const struct MapStrToExtendedProfile +{ + const Char* str; + ExtendedProfileName value; +} +strToExtendedProfile[] = +{ + {"none", NONE }, + {"main", MAIN }, + {"main10", MAIN10 }, + {"main-still-picture", MAINSTILLPICTURE }, + {"main-RExt", MAINREXT }, + {"high-throughput-RExt", HIGHTHROUGHPUTREXT }, + {"monochrome", MONOCHROME_8 }, + {"monochrome12", MONOCHROME_12 }, + {"monochrome16", MONOCHROME_16 }, + {"main12", MAIN_12 }, + {"main_422_10", MAIN_422_10 }, + {"main_422_12", MAIN_422_12 }, + {"main_444", MAIN_444 }, + {"main_444_10", MAIN_444_10 }, + {"main_444_12", MAIN_444_12 }, + {"main_444_16", MAIN_444_16 }, + {"main_intra", MAIN_INTRA }, + {"main_10_intra", MAIN_10_INTRA }, + {"main_12_intra", MAIN_12_INTRA }, + {"main_422_10_intra", MAIN_422_10_INTRA}, + {"main_422_12_intra", MAIN_422_12_INTRA}, + {"main_444_intra", MAIN_444_INTRA }, + {"main_444_10_intra", MAIN_444_10_INTRA}, + {"main_444_12_intra", MAIN_444_12_INTRA}, + {"main_444_16_intra", MAIN_444_16_INTRA} +}; + +static const ExtendedProfileName validRExtProfileNames[2/* intraConstraintFlag*/][4/* bit depth constraint 8=0, 10=1, 12=2, 16=3*/][4/*chroma format*/]= +{ + { + { MONOCHROME_8, NONE, NONE, MAIN_444 }, // 8-bit inter for 400, 420, 422 and 444 + { NONE, NONE, MAIN_422_10, MAIN_444_10 }, // 10-bit inter for 400, 420, 422 and 444 + { MONOCHROME_12, MAIN_12, MAIN_422_12, MAIN_444_12 }, // 12-bit inter for 400, 420, 422 and 444 + { MONOCHROME_16, NONE, NONE, MAIN_444_16 } // 16-bit inter for 400, 420, 422 and 444 (the latter is non standard used for development) + }, + { + { NONE, MAIN_INTRA, NONE, MAIN_444_INTRA }, // 8-bit intra for 400, 420, 422 and 444 + { NONE, MAIN_10_INTRA, MAIN_422_10_INTRA, MAIN_444_10_INTRA }, // 10-bit intra for 400, 420, 422 and 444 + { NONE, MAIN_12_INTRA, MAIN_422_12_INTRA, MAIN_444_12_INTRA }, // 12-bit intra for 400, 420, 422 and 444 + { NONE, NONE, NONE, MAIN_444_16_INTRA } // 16-bit intra for 400, 420, 422 and 444 + } +}; + +static const struct MapStrToTier +{ + const Char* str; + Level::Tier value; +} +strToTier[] = +{ + {"main", Level::MAIN}, + {"high", Level::HIGH}, +}; + +static const struct MapStrToLevel +{ + const Char* str; + Level::Name value; +} +strToLevel[] = +{ + {"none",Level::NONE}, + {"1", Level::LEVEL1}, + {"2", Level::LEVEL2}, + {"2.1", Level::LEVEL2_1}, + {"3", Level::LEVEL3}, + {"3.1", Level::LEVEL3_1}, + {"4", Level::LEVEL4}, + {"4.1", Level::LEVEL4_1}, + {"5", Level::LEVEL5}, + {"5.1", Level::LEVEL5_1}, + {"5.2", Level::LEVEL5_2}, + {"6", Level::LEVEL6}, + {"6.1", Level::LEVEL6_1}, + {"6.2", Level::LEVEL6_2}, + {"8.5", Level::LEVEL8_5}, +}; + +static const struct MapStrToCostMode +{ + const Char* str; + CostMode value; +} +strToCostMode[] = +{ + {"lossy", COST_STANDARD_LOSSY}, + {"sequence_level_lossless", COST_SEQUENCE_LEVEL_LOSSLESS}, + {"lossless", COST_LOSSLESS_CODING}, + {"mixed_lossless_lossy", COST_MIXED_LOSSLESS_LOSSY_CODING} +}; + +static const struct MapStrToScalingListMode +{ + const Char* str; + ScalingListMode value; +} +strToScalingListMode[] = +{ + {"0", SCALING_LIST_OFF}, + {"1", SCALING_LIST_DEFAULT}, + {"2", SCALING_LIST_FILE_READ}, + {"off", SCALING_LIST_OFF}, + {"default", SCALING_LIST_DEFAULT}, + {"file", SCALING_LIST_FILE_READ} +}; + +template +static std::string enumToString(P map[], UInt mapLen, const T val) +{ + for (UInt i = 0; i < mapLen; i++) + { + if (val == map[i].value) + { + return map[i].str; + } + } + return std::string(); +} + +template +static istream& readStrToEnum(P map[], UInt mapLen, istream &in, T &val) +{ + string str; + in >> str; + + for (UInt i = 0; i < mapLen; i++) + { + if (str == map[i].str) + { + val = map[i].value; + goto found; + } + } + /* not found */ + in.setstate(ios::failbit); +found: + return in; +} + +//inline to prevent compiler warnings for "unused static function" + +static inline istream& operator >> (istream &in, ExtendedProfileName &profile) +{ + return readStrToEnum(strToExtendedProfile, sizeof(strToExtendedProfile)/sizeof(*strToExtendedProfile), in, profile); +} + +namespace Level +{ + static inline istream& operator >> (istream &in, Tier &tier) + { + return readStrToEnum(strToTier, sizeof(strToTier)/sizeof(*strToTier), in, tier); + } + + static inline istream& operator >> (istream &in, Name &level) + { + return readStrToEnum(strToLevel, sizeof(strToLevel)/sizeof(*strToLevel), in, level); + } +} + +static inline istream& operator >> (istream &in, CostMode &mode) +{ + return readStrToEnum(strToCostMode, sizeof(strToCostMode)/sizeof(*strToCostMode), in, mode); +} + +static inline istream& operator >> (istream &in, ScalingListMode &mode) +{ + return readStrToEnum(strToScalingListMode, sizeof(strToScalingListMode)/sizeof(*strToScalingListMode), in, mode); +} + +template +struct SMultiValueInput +{ + const T minValIncl; + const T maxValIncl; // Use 0 for unlimited + const std::size_t minNumValuesIncl; + const std::size_t maxNumValuesIncl; // Use 0 for unlimited + std::vector values; + SMultiValueInput() : minValIncl(0), maxValIncl(0), minNumValuesIncl(0), maxNumValuesIncl(0), values() { } + SMultiValueInput(std::vector &defaults) : minValIncl(0), maxValIncl(0), minNumValuesIncl(0), maxNumValuesIncl(0), values(defaults) { } + SMultiValueInput(const T &minValue, const T &maxValue, std::size_t minNumberValues=0, std::size_t maxNumberValues=0) + : minValIncl(minValue), maxValIncl(maxValue), minNumValuesIncl(minNumberValues), maxNumValuesIncl(maxNumberValues), values() { } + SMultiValueInput(const T &minValue, const T &maxValue, std::size_t minNumberValues, std::size_t maxNumberValues, const T* defValues, const UInt numDefValues) + : minValIncl(minValue), maxValIncl(maxValue), minNumValuesIncl(minNumberValues), maxNumValuesIncl(maxNumberValues), values(defValues, defValues+numDefValues) { } + SMultiValueInput &operator=(const std::vector &userValues) { values=userValues; return *this; } + SMultiValueInput &operator=(const SMultiValueInput &userValues) { values=userValues.values; return *this; } +}; + +static inline istream& operator >> (istream &in, SMultiValueInput &values) +{ + values.values.clear(); + string str; + in >> str; + if (!str.empty()) + { + const Char *pStr=str.c_str(); + // soak up any whitespace + for(;isspace(*pStr);pStr++); + + while (*pStr != 0) + { + Char *eptr; + UInt val=strtoul(pStr, &eptr, 0); + if (*eptr!=0 && !isspace(*eptr) && *eptr!=',') + { + in.setstate(ios::failbit); + break; + } + if (valvalues.maxValIncl) + { + in.setstate(ios::failbit); + break; + } + + if (values.maxNumValuesIncl != 0 && values.values.size() >= values.maxNumValuesIncl) + { + in.setstate(ios::failbit); + break; + } + values.values.push_back(val); + // soak up any whitespace and up to 1 comma. + pStr=eptr; + for(;isspace(*pStr);pStr++); + if (*pStr == ',') pStr++; + for(;isspace(*pStr);pStr++); + } + } + if (values.values.size() < values.minNumValuesIncl) + { + in.setstate(ios::failbit); + } + return in; +} + +static inline istream& operator >> (istream &in, SMultiValueInput &values) +{ + values.values.clear(); + string str; + in >> str; + if (!str.empty()) + { + const Char *pStr=str.c_str(); + // soak up any whitespace + for(;isspace(*pStr);pStr++); + + while (*pStr != 0) + { + Char *eptr; + Int val=strtol(pStr, &eptr, 0); + if (*eptr!=0 && !isspace(*eptr) && *eptr!=',') + { + in.setstate(ios::failbit); + break; + } + if (valvalues.maxValIncl) + { + in.setstate(ios::failbit); + break; + } + + if (values.maxNumValuesIncl != 0 && values.values.size() >= values.maxNumValuesIncl) + { + in.setstate(ios::failbit); + break; + } + values.values.push_back(val); + // soak up any whitespace and up to 1 comma. + pStr=eptr; + for(;isspace(*pStr);pStr++); + if (*pStr == ',') pStr++; + for(;isspace(*pStr);pStr++); + } + } + if (values.values.size() < values.minNumValuesIncl) + { + in.setstate(ios::failbit); + } + return in; +} + +static inline istream& operator >> (istream &in, SMultiValueInput &values) +{ + values.values.clear(); + string str; + in >> str; + if (!str.empty()) + { + const Char *pStr=str.c_str(); + // soak up any whitespace + for(;isspace(*pStr);pStr++); + + while (*pStr != 0) + { + Char *eptr; + Int val=strtol(pStr, &eptr, 0); + if (*eptr!=0 && !isspace(*eptr) && *eptr!=',') + { + in.setstate(ios::failbit); + break; + } + if (valInt(values.maxValIncl)) + { + in.setstate(ios::failbit); + break; + } + + if (values.maxNumValuesIncl != 0 && values.values.size() >= values.maxNumValuesIncl) + { + in.setstate(ios::failbit); + break; + } + values.values.push_back(val!=0); + // soak up any whitespace and up to 1 comma. + pStr=eptr; + for(;isspace(*pStr);pStr++); + if (*pStr == ',') pStr++; + for(;isspace(*pStr);pStr++); + } + } + if (values.values.size() < values.minNumValuesIncl) + { + in.setstate(ios::failbit); + } + return in; +} + +static Void +automaticallySelectRExtProfile(const Bool bUsingGeneralRExtTools, + const Bool bUsingChromaQPAdjustment, + const Bool bUsingExtendedPrecision, + const Bool bIntraConstraintFlag, + UInt &bitDepthConstraint, + ChromaFormat &chromaFormatConstraint, + const Int maxBitDepth, + const ChromaFormat chromaFormat) +{ + // Try to choose profile, according to table in Q1013. + UInt trialBitDepthConstraint=maxBitDepth; + if (trialBitDepthConstraint<8) trialBitDepthConstraint=8; + else if (trialBitDepthConstraint==9 || trialBitDepthConstraint==11) trialBitDepthConstraint++; + else if (trialBitDepthConstraint>12) trialBitDepthConstraint=16; + + // both format and bit depth constraints are unspecified + if (bUsingExtendedPrecision || trialBitDepthConstraint==16) + { + bitDepthConstraint = 16; + chromaFormatConstraint = (!bIntraConstraintFlag && chromaFormat==CHROMA_400) ? CHROMA_400 : CHROMA_444; + } + else if (bUsingGeneralRExtTools) + { + if (chromaFormat == CHROMA_400 && !bIntraConstraintFlag) + { + bitDepthConstraint = 16; + chromaFormatConstraint = CHROMA_400; + } + else + { + bitDepthConstraint = trialBitDepthConstraint; + chromaFormatConstraint = CHROMA_444; + } + } + else if (chromaFormat == CHROMA_400) + { + if (bIntraConstraintFlag) + { + chromaFormatConstraint = CHROMA_420; // there is no intra 4:0:0 profile. + bitDepthConstraint = trialBitDepthConstraint; + } + else + { + chromaFormatConstraint = CHROMA_400; + bitDepthConstraint = trialBitDepthConstraint == 8 ? 8 : 12; + } + } + else + { + bitDepthConstraint = trialBitDepthConstraint; + chromaFormatConstraint = chromaFormat; + if (bUsingChromaQPAdjustment && chromaFormat == CHROMA_420) chromaFormatConstraint = CHROMA_422; // 4:2:0 cannot use the chroma qp tool. + if (chromaFormatConstraint == CHROMA_422 && bitDepthConstraint == 8) bitDepthConstraint = 10; // there is no 8-bit 4:2:2 profile. + if (chromaFormatConstraint == CHROMA_420 && !bIntraConstraintFlag) bitDepthConstraint = 12; // there is no 8 or 10-bit 4:2:0 inter RExt profile. + } +} +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** \param argc number of arguments + \param argv array of arguments + \retval true when success + */ +Bool TAppEncCfg::parseCfg( Int argc, Char* argv[] ) +{ + Bool do_help = false; + + string cfg_InputFile; + string cfg_BitstreamFile; + string cfg_ReconFile; + string cfg_dQPFile; + string cfg_ScalingListFile; + + Int tmpChromaFormat; + Int tmpInputChromaFormat; + Int tmpConstraintChromaFormat; + string inputColourSpaceConvert; + ExtendedProfileName extendedProfile; + Int saoOffsetBitShift[MAX_NUM_CHANNEL_TYPE]; + + // Multi-value input fields: // minval, maxval (incl), min_entries, max_entries (incl) [, default values, number of default values] + SMultiValueInput cfg_ColumnWidth (0, std::numeric_limits::max(), 0, std::numeric_limits::max()); + SMultiValueInput cfg_RowHeight (0, std::numeric_limits::max(), 0, std::numeric_limits::max()); + SMultiValueInput cfg_startOfCodedInterval (std::numeric_limits::min(), std::numeric_limits::max(), 0, 1<<16); + SMultiValueInput cfg_codedPivotValue (std::numeric_limits::min(), std::numeric_limits::max(), 0, 1<<16); + SMultiValueInput cfg_targetPivotValue (std::numeric_limits::min(), std::numeric_limits::max(), 0, 1<<16); + + const UInt defaultInputKneeCodes[3] = { 600, 800, 900 }; + const UInt defaultOutputKneeCodes[3] = { 100, 250, 450 }; + SMultiValueInput cfg_kneeSEIInputKneePointValue (1, 999, 0, 999, defaultInputKneeCodes, sizeof(defaultInputKneeCodes )/sizeof(UInt)); + SMultiValueInput cfg_kneeSEIOutputKneePointValue (0, 1000, 0, 999, defaultOutputKneeCodes, sizeof(defaultOutputKneeCodes)/sizeof(UInt)); + const Int defaultPrimaryCodes[6] = { 0,50000, 0,0, 50000,0 }; + const Int defaultWhitePointCode[2] = { 16667, 16667 }; + SMultiValueInput cfg_DisplayPrimariesCode (0, 50000, 3, 3, defaultPrimaryCodes, sizeof(defaultPrimaryCodes )/sizeof(Int)); + SMultiValueInput cfg_DisplayWhitePointCode (0, 50000, 2, 2, defaultWhitePointCode, sizeof(defaultWhitePointCode)/sizeof(Int)); + + SMultiValueInput cfg_timeCodeSeiTimeStampFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiNumUnitFieldBasedFlag(0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiCountingType (0, 6, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiFullTimeStampFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiDiscontinuityFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiCntDroppedFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiNumberOfFrames (0,511, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiSecondsValue (0, 59, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiMinutesValue (0, 59, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiHoursValue (0, 23, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiSecondsFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiMinutesFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiHoursFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiTimeOffsetLength (0, 31, 0, MAX_TIMECODE_SEI_SETS); + SMultiValueInput cfg_timeCodeSeiTimeOffsetValue (std::numeric_limits::min(), std::numeric_limits::max(), 0, MAX_TIMECODE_SEI_SETS); + + po::Options opts; + opts.addOptions() + ("help", do_help, false, "this help text") + ("c", po::parseConfigFile, "configuration file name") + + // File, I/O and source parameters + ("InputFile,i", cfg_InputFile, string(""), "Original YUV input file name") + ("BitstreamFile,b", cfg_BitstreamFile, string(""), "Bitstream output file name") + ("ReconFile,o", cfg_ReconFile, string(""), "Reconstructed YUV output file name") + ("SourceWidth,-wdt", m_iSourceWidth, 0, "Source picture width") + ("SourceHeight,-hgt", m_iSourceHeight, 0, "Source picture height") + ("InputBitDepth", m_inputBitDepth[CHANNEL_TYPE_LUMA], 8, "Bit-depth of input file") + ("OutputBitDepth", m_outputBitDepth[CHANNEL_TYPE_LUMA], 0, "Bit-depth of output file (default:InternalBitDepth)") + ("MSBExtendedBitDepth", m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA], 0, "bit depth of luma component after addition of MSBs of value 0 (used for synthesising High Dynamic Range source material). (default:InputBitDepth)") + ("InternalBitDepth", m_internalBitDepth[CHANNEL_TYPE_LUMA], 0, "Bit-depth the codec operates at. (default:MSBExtendedBitDepth). If different to MSBExtendedBitDepth, source data will be converted") + ("InputBitDepthC", m_inputBitDepth[CHANNEL_TYPE_CHROMA], 0, "As per InputBitDepth but for chroma component. (default:InputBitDepth)") + ("OutputBitDepthC", m_outputBitDepth[CHANNEL_TYPE_CHROMA], 0, "As per OutputBitDepth but for chroma component. (default:InternalBitDepthC)") + ("MSBExtendedBitDepthC", m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA], 0, "As per MSBExtendedBitDepth but for chroma component. (default:MSBExtendedBitDepth)") + ("InternalBitDepthC", m_internalBitDepth[CHANNEL_TYPE_CHROMA], 0, "As per InternalBitDepth but for chroma component. (default:InternalBitDepth)") + ("ExtendedPrecision", m_useExtendedPrecision, false, "Increased internal accuracies to support high bit depths (not valid in V1 profiles)") + ("HighPrecisionPredictionWeighting", m_useHighPrecisionPredictionWeighting, false, "Use high precision option for weighted prediction (not valid in V1 profiles)") + ("InputColourSpaceConvert", inputColourSpaceConvert, string(""), "Colour space conversion to apply to input video. Permitted values are (empty string=UNCHANGED) " + getListOfColourSpaceConverts(true)) + ("SNRInternalColourSpace", m_snrInternalColourSpace, false, "If true, then no colour space conversion is applied prior to SNR, otherwise inverse of input is applied.") + ("OutputInternalColourSpace", m_outputInternalColourSpace, false, "If true, then no colour space conversion is applied for reconstructed video, otherwise inverse of input is applied.") + ("InputChromaFormat", tmpInputChromaFormat, 420, "InputChromaFormatIDC") + ("MSEBasedSequencePSNR", m_printMSEBasedSequencePSNR, false, "0 (default) emit sequence PSNR only as a linear average of the frame PSNRs, 1 = also emit a sequence PSNR based on an average of the frame MSEs") + ("PrintFrameMSE", m_printFrameMSE, false, "0 (default) emit only bit count and PSNRs for each frame, 1 = also emit MSE values") + ("PrintSequenceMSE", m_printSequenceMSE, false, "0 (default) emit only bit rate and PSNRs for the whole sequence, 1 = also emit MSE values") + ("CabacZeroWordPaddingEnabled", m_cabacZeroWordPaddingEnabled, false, "0 (default) do not add conforming cabac-zero-words to bit streams, 1 = add cabac-zero-words") + ("ChromaFormatIDC,-cf", tmpChromaFormat, 0, "ChromaFormatIDC (400|420|422|444 or set 0 (default) for same as InputChromaFormat)") + ("ConformanceMode", m_conformanceWindowMode, 0, "Deprecated alias of ConformanceWindowMode") + ("ConformanceWindowMode", m_conformanceWindowMode, 0, "Window conformance mode (0: no window, 1:automatic padding, 2:padding, 3:conformance") + ("HorizontalPadding,-pdx", m_aiPad[0], 0, "Horizontal source padding for conformance window mode 2") + ("VerticalPadding,-pdy", m_aiPad[1], 0, "Vertical source padding for conformance window mode 2") + ("ConfLeft", m_confWinLeft, 0, "Deprecated alias of ConfWinLeft") + ("ConfRight", m_confWinRight, 0, "Deprecated alias of ConfWinRight") + ("ConfTop", m_confWinTop, 0, "Deprecated alias of ConfWinTop") + ("ConfBottom", m_confWinBottom, 0, "Deprecated alias of ConfWinBottom") + ("ConfWinLeft", m_confWinLeft, 0, "Left offset for window conformance mode 3") + ("ConfWinRight", m_confWinRight, 0, "Right offset for window conformance mode 3") + ("ConfWinTop", m_confWinTop, 0, "Top offset for window conformance mode 3") + ("ConfWinBottom", m_confWinBottom, 0, "Bottom offset for window conformance mode 3") + ("FrameRate,-fr", m_iFrameRate, 0, "Frame rate") + ("FrameSkip,-fs", m_FrameSkip, 0u, "Number of frames to skip at start of input YUV") + ("FramesToBeEncoded,f", m_framesToBeEncoded, 0, "Number of frames to be encoded (default=all)") + + //Field coding parameters + ("FieldCoding", m_isField, false, "Signals if it's a field based coding") + ("TopFieldFirst, Tff", m_isTopFieldFirst, false, "In case of field based coding, signals whether if it's a top field first or not") + + // Profile and level + ("Profile", extendedProfile, NONE, "Profile name to use for encoding. Use main (for main), main10 (for main10), main-still-picture, main-RExt (for Range Extensions profile), any of the RExt specific profile names, or none") + ("Level", m_level, Level::NONE, "Level limit to be used, eg 5.1, or none") + ("Tier", m_levelTier, Level::MAIN, "Tier to use for interpretation of --Level (main or high only)") + ("MaxBitDepthConstraint", m_bitDepthConstraint, 0u, "Bit depth to use for profile-constraint for RExt profiles. 0=automatically choose based upon other parameters") + ("MaxChromaFormatConstraint", tmpConstraintChromaFormat, 0, "Chroma-format to use for the profile-constraint for RExt profiles. 0=automatically choose based upon other parameters") + ("IntraConstraintFlag", m_intraConstraintFlag, false, "Value of general_intra_constraint_flag to use for RExt profiles (not used if an explicit RExt sub-profile is specified)") + ("LowerBitRateConstraintFlag", m_lowerBitRateConstraintFlag, true, "Value of general_lower_bit_rate_constraint_flag to use for RExt profiles") + + ("ProgressiveSource", m_progressiveSourceFlag, false, "Indicate that source is progressive") + ("InterlacedSource", m_interlacedSourceFlag, false, "Indicate that source is interlaced") + ("NonPackedSource", m_nonPackedConstraintFlag, false, "Indicate that source does not contain frame packing") + ("FrameOnly", m_frameOnlyConstraintFlag, false, "Indicate that the bitstream contains only frames") + + // Unit definition parameters + ("MaxCUWidth", m_uiMaxCUWidth, 64u) + ("MaxCUHeight", m_uiMaxCUHeight, 64u) + // todo: remove defaults from MaxCUSize + ("MaxCUSize,s", m_uiMaxCUWidth, 64u, "Maximum CU size") + ("MaxCUSize,s", m_uiMaxCUHeight, 64u, "Maximum CU size") + ("MaxPartitionDepth,h", m_uiMaxCUDepth, 4u, "CU depth") + + ("QuadtreeTULog2MaxSize", m_uiQuadtreeTULog2MaxSize, 6u, "Maximum TU size in logarithm base 2") + ("QuadtreeTULog2MinSize", m_uiQuadtreeTULog2MinSize, 2u, "Minimum TU size in logarithm base 2") + + ("QuadtreeTUMaxDepthIntra", m_uiQuadtreeTUMaxDepthIntra, 1u, "Depth of TU tree for intra CUs") + ("QuadtreeTUMaxDepthInter", m_uiQuadtreeTUMaxDepthInter, 2u, "Depth of TU tree for inter CUs") + + // Coding structure paramters + ("IntraPeriod,-ip", m_iIntraPeriod, -1, "Intra period in frames, (-1: only first frame)") +#if ALLOW_RECOVERY_POINT_AS_RAP + ("DecodingRefreshType,-dr", m_iDecodingRefreshType, 0, "Intra refresh type (0:none 1:CRA 2:IDR 3:RecPointSEI)") +#else + ("DecodingRefreshType,-dr", m_iDecodingRefreshType, 0, "Intra refresh type (0:none 1:CRA 2:IDR)") +#endif + ("GOPSize,g", m_iGOPSize, 1, "GOP size of temporal structure") + + // motion search options + ("FastSearch", m_iFastSearch, 1, "0:Full search 1:Diamond 2:PMVFAST") + ("SearchRange,-sr", m_iSearchRange, 96, "Motion search range") + ("BipredSearchRange", m_bipredSearchRange, 4, "Motion search range for bipred refinement") + ("HadamardME", m_bUseHADME, true, "Hadamard ME for fractional-pel") + ("ASR", m_bUseASR, false, "Adaptive motion search range") + + // Mode decision parameters + ("LambdaModifier0,-LM0", m_adLambdaModifier[ 0 ], ( Double )1.0, "Lambda modifier for temporal layer 0") + ("LambdaModifier1,-LM1", m_adLambdaModifier[ 1 ], ( Double )1.0, "Lambda modifier for temporal layer 1") + ("LambdaModifier2,-LM2", m_adLambdaModifier[ 2 ], ( Double )1.0, "Lambda modifier for temporal layer 2") + ("LambdaModifier3,-LM3", m_adLambdaModifier[ 3 ], ( Double )1.0, "Lambda modifier for temporal layer 3") + ("LambdaModifier4,-LM4", m_adLambdaModifier[ 4 ], ( Double )1.0, "Lambda modifier for temporal layer 4") + ("LambdaModifier5,-LM5", m_adLambdaModifier[ 5 ], ( Double )1.0, "Lambda modifier for temporal layer 5") + ("LambdaModifier6,-LM6", m_adLambdaModifier[ 6 ], ( Double )1.0, "Lambda modifier for temporal layer 6") + + /* Quantization parameters */ + ("QP,q", m_fQP, 30.0, "Qp value, if value is float, QP is switched once during encoding") + ("DeltaQpRD,-dqr", m_uiDeltaQpRD, 0u, "max dQp offset for slice") + ("MaxDeltaQP,d", m_iMaxDeltaQP, 0, "max dQp offset for block") + ("MaxCuDQPDepth,-dqd", m_iMaxCuDQPDepth, 0, "max depth for a minimum CuDQP") + ("MaxCUChromaQpAdjustmentDepth", m_maxCUChromaQpAdjustmentDepth, -1, "Maximum depth for CU chroma Qp adjustment - set less than 0 to disable") + + ("CbQpOffset,-cbqpofs", m_cbQpOffset, 0, "Chroma Cb QP Offset") + ("CrQpOffset,-crqpofs", m_crQpOffset, 0, "Chroma Cr QP Offset") + +#if ADAPTIVE_QP_SELECTION + ("AdaptiveQpSelection,-aqps", m_bUseAdaptQpSelect, false, "AdaptiveQpSelection") +#endif + + ("AdaptiveQP,-aq", m_bUseAdaptiveQP, false, "QP adaptation based on a psycho-visual model") + ("MaxQPAdaptationRange,-aqr", m_iQPAdaptationRange, 6, "QP adaptation range") + ("dQPFile,m", cfg_dQPFile, string(""), "dQP file name") + ("RDOQ", m_useRDOQ, true) + ("RDOQTS", m_useRDOQTS, true) + ("RDpenalty", m_rdPenalty, 0, "RD-penalty for 32x32 TU for intra in non-intra slices. 0:disabled 1:RD-penalty 2:maximum RD-penalty") + + // Deblocking filter parameters + ("LoopFilterDisable", m_bLoopFilterDisable, false) + ("LoopFilterOffsetInPPS", m_loopFilterOffsetInPPS, false) + ("LoopFilterBetaOffset_div2", m_loopFilterBetaOffsetDiv2, 0) + ("LoopFilterTcOffset_div2", m_loopFilterTcOffsetDiv2, 0) + ("DeblockingFilterControlPresent", m_DeblockingFilterControlPresent, false) + ("DeblockingFilterMetric", m_DeblockingFilterMetric, false) + + // Coding tools + ("AMP", m_enableAMP, true, "Enable asymmetric motion partitions") + ("CrossComponentPrediction", m_useCrossComponentPrediction, false, "Enable the use of cross-component prediction (not valid in V1 profiles)") + ("ReconBasedCrossCPredictionEstimate", m_reconBasedCrossCPredictionEstimate, false, "When determining the alpha value for cross-component prediction, use the decoded residual rather than the pre-transform encoder-side residual") + ("SaoLumaOffsetBitShift", saoOffsetBitShift[CHANNEL_TYPE_LUMA], 0, "Specify the luma SAO bit-shift. If negative, automatically calculate a suitable value based upon bit depth and initial QP") + ("SaoChromaOffsetBitShift", saoOffsetBitShift[CHANNEL_TYPE_CHROMA], 0, "Specify the chroma SAO bit-shift. If negative, automatically calculate a suitable value based upon bit depth and initial QP") + ("TransformSkip", m_useTransformSkip, false, "Intra transform skipping") + ("TransformSkipFast", m_useTransformSkipFast, false, "Fast intra transform skipping") + ("TransformSkipLog2MaxSize", m_transformSkipLog2MaxSize, 2U, "Specify transform-skip maximum size. Minimum 2. (not valid in V1 profiles)") + ("ImplicitResidualDPCM", m_useResidualDPCM[RDPCM_SIGNAL_IMPLICIT], false, "Enable implicitly signalled residual DPCM for intra (also known as sample-adaptive intra predict) (not valid in V1 profiles)") + ("ExplicitResidualDPCM", m_useResidualDPCM[RDPCM_SIGNAL_EXPLICIT], false, "Enable explicitly signalled residual DPCM for inter (not valid in V1 profiles)") + ("ResidualRotation", m_useResidualRotation, false, "Enable rotation of transform-skipped and transquant-bypassed TUs through 180 degrees prior to entropy coding (not valid in V1 profiles)") + ("SingleSignificanceMapContext", m_useSingleSignificanceMapContext, false, "Enable, for transform-skipped and transquant-bypassed TUs, the selection of a single significance map context variable for all coefficients (not valid in V1 profiles)") + ("GolombRiceParameterAdaptation", m_useGolombRiceParameterAdaptation, false, "Enable the adaptation of the Golomb-Rice parameter over the course of each slice") + ("AlignCABACBeforeBypass", m_alignCABACBeforeBypass, false, "Align the CABAC engine to a defined fraction of a bit prior to coding bypass data. Must be 1 in high bit rate profile, 0 otherwise" ) + ("SAO", m_bUseSAO, true, "Enable Sample Adaptive Offset") + ("MaxNumOffsetsPerPic", m_maxNumOffsetsPerPic, 2048, "Max number of SAO offset per picture (Default: 2048)") + ("SAOLcuBoundary", m_saoCtuBoundary, false, "0: right/bottom CTU boundary areas skipped from SAO parameter estimation, 1: non-deblocked pixels are used for those areas") + ("SliceMode", m_sliceMode, 0, "0: Disable all Recon slice limits, 1: Enforce max # of CTUs, 2: Enforce max # of bytes, 3:specify tiles per dependent slice") + ("SliceArgument", m_sliceArgument, 0, "Depending on SliceMode being:" + "\t1: max number of CTUs per slice" + "\t2: max number of bytes per slice" + "\t3: max number of tiles per slice") + ("SliceSegmentMode", m_sliceSegmentMode, 0, "0: Disable all slice segment limits, 1: Enforce max # of CTUs, 2: Enforce max # of bytes, 3:specify tiles per dependent slice") + ("SliceSegmentArgument", m_sliceSegmentArgument, 0, "Depending on SliceSegmentMode being:" + "\t1: max number of CTUs per slice segment" + "\t2: max number of bytes per slice segment" + "\t3: max number of tiles per slice segment") + ("LFCrossSliceBoundaryFlag", m_bLFCrossSliceBoundaryFlag, true) + + ("ConstrainedIntraPred", m_bUseConstrainedIntraPred, false, "Constrained Intra Prediction") + ("PCMEnabledFlag", m_usePCM, false) + ("PCMLog2MaxSize", m_pcmLog2MaxSize, 5u) + ("PCMLog2MinSize", m_uiPCMLog2MinSize, 3u) + + ("PCMInputBitDepthFlag", m_bPCMInputBitDepthFlag, true) + ("PCMFilterDisableFlag", m_bPCMFilterDisableFlag, false) + ("IntraReferenceSmoothing", m_enableIntraReferenceSmoothing, true, "0: Disable use of intra reference smoothing. 1: Enable use of intra reference smoothing (not valid in V1 profiles)") + ("WeightedPredP,-wpP", m_useWeightedPred, false, "Use weighted prediction in P slices") + ("WeightedPredB,-wpB", m_useWeightedBiPred, false, "Use weighted (bidirectional) prediction in B slices") + ("Log2ParallelMergeLevel", m_log2ParallelMergeLevel, 2u, "Parallel merge estimation region") + //deprecated copies of renamed tile parameters + ("UniformSpacingIdc", m_tileUniformSpacingFlag, false, "deprecated alias of TileUniformSpacing") + ("ColumnWidthArray", cfg_ColumnWidth, cfg_ColumnWidth, "deprecated alias of TileColumnWidthArray") + ("RowHeightArray", cfg_RowHeight, cfg_RowHeight, "deprecated alias of TileRowHeightArray") + + ("TileUniformSpacing", m_tileUniformSpacingFlag, false, "Indicates that tile columns and rows are distributed uniformly") + ("NumTileColumnsMinus1", m_numTileColumnsMinus1, 0, "Number of tile columns in a picture minus 1") + ("NumTileRowsMinus1", m_numTileRowsMinus1, 0, "Number of rows in a picture minus 1") + ("TileColumnWidthArray", cfg_ColumnWidth, cfg_ColumnWidth, "Array containing tile column width values in units of CTU") + ("TileRowHeightArray", cfg_RowHeight, cfg_RowHeight, "Array containing tile row height values in units of CTU") + ("LFCrossTileBoundaryFlag", m_bLFCrossTileBoundaryFlag, true, "1: cross-tile-boundary loop filtering. 0:non-cross-tile-boundary loop filtering") + ("WaveFrontSynchro", m_iWaveFrontSynchro, 0, "0: no synchro; 1 synchro with top-right-right") + ("ScalingList", m_useScalingListId, SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile") + ("ScalingListFile", cfg_ScalingListFile, string(""), "Scaling list file name. Use an empty string to produce help.") + ("SignHideFlag,-SBH", m_signHideFlag, 1) + ("MaxNumMergeCand", m_maxNumMergeCand, 5u, "Maximum number of merge candidates") + /* Misc. */ + ("SEIDecodedPictureHash", m_decodedPictureHashSEIEnabled, 0, "Control generation of decode picture hash SEI messages\n" + "\t3: checksum\n" + "\t2: CRC\n" + "\t1: use MD5\n" + "\t0: disable") + ("SEIpictureDigest", m_decodedPictureHashSEIEnabled, 0, "deprecated alias for SEIDecodedPictureHash") + ("TMVPMode", m_TMVPModeId, 1, "TMVP mode 0: TMVP disable for all slices. 1: TMVP enable for all slices (default) 2: TMVP enable for certain slices only") + ("FEN", m_bUseFastEnc, false, "fast encoder setting") + ("ECU", m_bUseEarlyCU, false, "Early CU setting") + ("FDM", m_useFastDecisionForMerge, true, "Fast decision for Merge RD Cost") + ("CFM", m_bUseCbfFastMode, false, "Cbf fast mode setting") + ("ESD", m_useEarlySkipDetection, false, "Early SKIP detection setting") + ( "RateControl", m_RCEnableRateControl, false, "Rate control: enable rate control" ) + ( "TargetBitrate", m_RCTargetBitrate, 0, "Rate control: target bit-rate" ) + ( "KeepHierarchicalBit", m_RCKeepHierarchicalBit, 0, "Rate control: 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation" ) + ( "LCULevelRateControl", m_RCLCULevelRC, true, "Rate control: true: CTU level RC; false: picture level RC" ) + ( "RCLCUSeparateModel", m_RCUseLCUSeparateModel, true, "Rate control: use CTU level separate R-lambda model" ) + ( "InitialQP", m_RCInitialQP, 0, "Rate control: initial QP" ) + ( "RCForceIntraQP", m_RCForceIntraQP, false, "Rate control: force intra QP to be equal to initial QP" ) + + ("TransquantBypassEnableFlag", m_TransquantBypassEnableFlag, false, "transquant_bypass_enable_flag indicator in PPS") + ("CUTransquantBypassFlagForce", m_CUTransquantBypassFlagForce, false, "Force transquant bypass mode, when transquant_bypass_enable_flag is enabled") + ("CostMode", m_costMode, COST_STANDARD_LOSSY, "Use alternative cost functions: choose between 'lossy', 'sequence_level_lossless', 'lossless' (which forces QP to " MACRO_TO_STRING(LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP) ") and 'mixed_lossless_lossy' (which used QP'=" MACRO_TO_STRING(LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME) " for pre-estimates of transquant-bypass blocks).") + ("RecalculateQPAccordingToLambda", m_recalculateQPAccordingToLambda, false, "Recalculate QP values according to lambda values. Do not suggest to be enabled in all intra case") + ("StrongIntraSmoothing,-sis", m_useStrongIntraSmoothing, true, "Enable strong intra smoothing for 32x32 blocks") + ("SEIActiveParameterSets", m_activeParameterSetsSEIEnabled, 0, "Enable generation of active parameter sets SEI messages") + ("VuiParametersPresent,-vui", m_vuiParametersPresentFlag, false, "Enable generation of vui_parameters()") + ("AspectRatioInfoPresent", m_aspectRatioInfoPresentFlag, false, "Signals whether aspect_ratio_idc is present") + ("AspectRatioIdc", m_aspectRatioIdc, 0, "aspect_ratio_idc") + ("SarWidth", m_sarWidth, 0, "horizontal size of the sample aspect ratio") + ("SarHeight", m_sarHeight, 0, "vertical size of the sample aspect ratio") + ("OverscanInfoPresent", m_overscanInfoPresentFlag, false, "Indicates whether conformant decoded pictures are suitable for display using overscan\n") + ("OverscanAppropriate", m_overscanAppropriateFlag, false, "Indicates whether conformant decoded pictures are suitable for display using overscan\n") + ("VideoSignalTypePresent", m_videoSignalTypePresentFlag, false, "Signals whether video_format, video_full_range_flag, and colour_description_present_flag are present") + ("VideoFormat", m_videoFormat, 5, "Indicates representation of pictures") + ("VideoFullRange", m_videoFullRangeFlag, false, "Indicates the black level and range of luma and chroma signals") + ("ColourDescriptionPresent", m_colourDescriptionPresentFlag, false, "Signals whether colour_primaries, transfer_characteristics and matrix_coefficients are present") + ("ColourPrimaries", m_colourPrimaries, 2, "Indicates chromaticity coordinates of the source primaries") + ("TransferCharacteristics", m_transferCharacteristics, 2, "Indicates the opto-electronic transfer characteristics of the source") + ("MatrixCoefficients", m_matrixCoefficients, 2, "Describes the matrix coefficients used in deriving luma and chroma from RGB primaries") + ("ChromaLocInfoPresent", m_chromaLocInfoPresentFlag, false, "Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present") + ("ChromaSampleLocTypeTopField", m_chromaSampleLocTypeTopField, 0, "Specifies the location of chroma samples for top field") + ("ChromaSampleLocTypeBottomField", m_chromaSampleLocTypeBottomField, 0, "Specifies the location of chroma samples for bottom field") + ("NeutralChromaIndication", m_neutralChromaIndicationFlag, false, "Indicates that the value of all decoded chroma samples is equal to 1<<(BitDepthCr-1)") + ("DefaultDisplayWindowFlag", m_defaultDisplayWindowFlag, false, "Indicates the presence of the Default Window parameters") + ("DefDispWinLeftOffset", m_defDispWinLeftOffset, 0, "Specifies the left offset of the default display window from the conformance window") + ("DefDispWinRightOffset", m_defDispWinRightOffset, 0, "Specifies the right offset of the default display window from the conformance window") + ("DefDispWinTopOffset", m_defDispWinTopOffset, 0, "Specifies the top offset of the default display window from the conformance window") + ("DefDispWinBottomOffset", m_defDispWinBottomOffset, 0, "Specifies the bottom offset of the default display window from the conformance window") + ("FrameFieldInfoPresentFlag", m_frameFieldInfoPresentFlag, false, "Indicates that pic_struct and field coding related values are present in picture timing SEI messages") + ("PocProportionalToTimingFlag", m_pocProportionalToTimingFlag, false, "Indicates that the POC value is proportional to the output time w.r.t. first picture in CVS") + ("NumTicksPocDiffOneMinus1", m_numTicksPocDiffOneMinus1, 0, "Number of ticks minus 1 that for a POC difference of one") + ("BitstreamRestriction", m_bitstreamRestrictionFlag, false, "Signals whether bitstream restriction parameters are present") + ("TilesFixedStructure", m_tilesFixedStructureFlag, false, "Indicates that each active picture parameter set has the same values of the syntax elements related to tiles") + ("MotionVectorsOverPicBoundaries", m_motionVectorsOverPicBoundariesFlag, false, "Indicates that no samples outside the picture boundaries are used for inter prediction") + ("MaxBytesPerPicDenom", m_maxBytesPerPicDenom, 2, "Indicates a number of bytes not exceeded by the sum of the sizes of the VCL NAL units associated with any coded picture") + ("MaxBitsPerMinCuDenom", m_maxBitsPerMinCuDenom, 1, "Indicates an upper bound for the number of bits of coding_unit() data") + ("Log2MaxMvLengthHorizontal", m_log2MaxMvLengthHorizontal, 15, "Indicate the maximum absolute value of a decoded horizontal MV component in quarter-pel luma units") + ("Log2MaxMvLengthVertical", m_log2MaxMvLengthVertical, 15, "Indicate the maximum absolute value of a decoded vertical MV component in quarter-pel luma units") + ("SEIRecoveryPoint", m_recoveryPointSEIEnabled, 0, "Control generation of recovery point SEI messages") + ("SEIBufferingPeriod", m_bufferingPeriodSEIEnabled, 0, "Control generation of buffering period SEI messages") + ("SEIPictureTiming", m_pictureTimingSEIEnabled, 0, "Control generation of picture timing SEI messages") + ("SEIToneMappingInfo", m_toneMappingInfoSEIEnabled, false, "Control generation of Tone Mapping SEI messages") + ("SEIToneMapId", m_toneMapId, 0, "Specifies Id of Tone Mapping SEI message for a given session") + ("SEIToneMapCancelFlag", m_toneMapCancelFlag, false, "Indicates that Tone Mapping SEI message cancels the persistence or follows") + ("SEIToneMapPersistenceFlag", m_toneMapPersistenceFlag, true, "Specifies the persistence of the Tone Mapping SEI message") + ("SEIToneMapCodedDataBitDepth", m_toneMapCodedDataBitDepth, 8, "Specifies Coded Data BitDepth of Tone Mapping SEI messages") + ("SEIToneMapTargetBitDepth", m_toneMapTargetBitDepth, 8, "Specifies Output BitDepth of Tone mapping function") + ("SEIToneMapModelId", m_toneMapModelId, 0, "Specifies Model utilized for mapping coded data into target_bit_depth range\n" + "\t0: linear mapping with clipping\n" + "\t1: sigmoidal mapping\n" + "\t2: user-defined table mapping\n" + "\t3: piece-wise linear mapping\n" + "\t4: luminance dynamic range information ") + ("SEIToneMapMinValue", m_toneMapMinValue, 0, "Specifies the minimum value in mode 0") + ("SEIToneMapMaxValue", m_toneMapMaxValue, 1023, "Specifies the maximum value in mode 0") + ("SEIToneMapSigmoidMidpoint", m_sigmoidMidpoint, 512, "Specifies the centre point in mode 1") + ("SEIToneMapSigmoidWidth", m_sigmoidWidth, 960, "Specifies the distance between 5% and 95% values of the target_bit_depth in mode 1") + ("SEIToneMapStartOfCodedInterval", cfg_startOfCodedInterval, cfg_startOfCodedInterval, "Array of user-defined mapping table") + ("SEIToneMapNumPivots", m_numPivots, 0, "Specifies the number of pivot points in mode 3") + ("SEIToneMapCodedPivotValue", cfg_codedPivotValue, cfg_codedPivotValue, "Array of pivot point") + ("SEIToneMapTargetPivotValue", cfg_targetPivotValue, cfg_targetPivotValue, "Array of pivot point") + ("SEIToneMapCameraIsoSpeedIdc", m_cameraIsoSpeedIdc, 0, "Indicates the camera ISO speed for daylight illumination") + ("SEIToneMapCameraIsoSpeedValue", m_cameraIsoSpeedValue, 400, "Specifies the camera ISO speed for daylight illumination of Extended_ISO") + ("SEIToneMapExposureIndexIdc", m_exposureIndexIdc, 0, "Indicates the exposure index setting of the camera") + ("SEIToneMapExposureIndexValue", m_exposureIndexValue, 400, "Specifies the exposure index setting of the camera of Extended_ISO") + ("SEIToneMapExposureCompensationValueSignFlag", m_exposureCompensationValueSignFlag, 0, "Specifies the sign of ExposureCompensationValue") + ("SEIToneMapExposureCompensationValueNumerator", m_exposureCompensationValueNumerator, 0, "Specifies the numerator of ExposureCompensationValue") + ("SEIToneMapExposureCompensationValueDenomIdc", m_exposureCompensationValueDenomIdc, 2, "Specifies the denominator of ExposureCompensationValue") + ("SEIToneMapRefScreenLuminanceWhite", m_refScreenLuminanceWhite, 350, "Specifies reference screen brightness setting in units of candela per square metre") + ("SEIToneMapExtendedRangeWhiteLevel", m_extendedRangeWhiteLevel, 800, "Indicates the luminance dynamic range") + ("SEIToneMapNominalBlackLevelLumaCodeValue", m_nominalBlackLevelLumaCodeValue, 16, "Specifies luma sample value of the nominal black level assigned decoded pictures") + ("SEIToneMapNominalWhiteLevelLumaCodeValue", m_nominalWhiteLevelLumaCodeValue, 235, "Specifies luma sample value of the nominal white level assigned decoded pictures") + ("SEIToneMapExtendedWhiteLevelLumaCodeValue", m_extendedWhiteLevelLumaCodeValue, 300, "Specifies luma sample value of the extended dynamic range assigned decoded pictures") + ("SEIChromaSamplingFilterHint", m_chromaSamplingFilterSEIenabled, false, "Control generation of the chroma sampling filter hint SEI message") + ("SEIChromaSamplingHorizontalFilterType", m_chromaSamplingHorFilterIdc, 2, "Defines the Index of the chroma sampling horizontal filter\n" + "\t0: unspecified - Chroma filter is unknown or is determined by the application" + "\t1: User-defined - Filter coefficients are specified in the chroma sampling filter hint SEI message" + "\t2: Standards-defined - ITU-T Rec. T.800 | ISO/IEC15444-1, 5/3 filter") + ("SEIChromaSamplingVerticalFilterType", m_chromaSamplingVerFilterIdc, 2, "Defines the Index of the chroma sampling vertical filter\n" + "\t0: unspecified - Chroma filter is unknown or is determined by the application" + "\t1: User-defined - Filter coefficients are specified in the chroma sampling filter hint SEI message" + "\t2: Standards-defined - ITU-T Rec. T.800 | ISO/IEC15444-1, 5/3 filter") + ("SEIFramePacking", m_framePackingSEIEnabled, 0, "Control generation of frame packing SEI messages") + ("SEIFramePackingType", m_framePackingSEIType, 0, "Define frame packing arrangement\n" + "\t3: side by side - frames are displayed horizontally\n" + "\t4: top bottom - frames are displayed vertically\n" + "\t5: frame alternation - one frame is alternated with the other") + ("SEIFramePackingId", m_framePackingSEIId, 0, "Id of frame packing SEI message for a given session") + ("SEIFramePackingQuincunx", m_framePackingSEIQuincunx, 0, "Indicate the presence of a Quincunx type video frame") + ("SEIFramePackingInterpretation", m_framePackingSEIInterpretation, 0, "Indicate the interpretation of the frame pair\n" + "\t0: unspecified\n" + "\t1: stereo pair, frame0 represents left view\n" + "\t2: stereo pair, frame0 represents right view") + ("SEISegmentedRectFramePacking", m_segmentedRectFramePackingSEIEnabled, 0, "Controls generation of segmented rectangular frame packing SEI messages") + ("SEISegmentedRectFramePackingCancel", m_segmentedRectFramePackingSEICancel, false, "If equal to 1, cancels the persistence of any previous SRFPA SEI message") + ("SEISegmentedRectFramePackingType", m_segmentedRectFramePackingSEIType, 0, "Specifies the arrangement of the frames in the reconstructed picture") + ("SEISegmentedRectFramePackingPersistence", m_segmentedRectFramePackingSEIPersistence, false, "If equal to 0, the SEI applies to the current frame only") + ("SEIDisplayOrientation", m_displayOrientationSEIAngle, 0, "Control generation of display orientation SEI messages\n" + "\tN: 0 < N < (2^16 - 1) enable display orientation SEI message with anticlockwise_rotation = N and display_orientation_repetition_period = 1\n" + "\t0: disable") + ("SEITemporalLevel0Index", m_temporalLevel0IndexSEIEnabled, 0, "Control generation of temporal level 0 index SEI messages") + ("SEIGradualDecodingRefreshInfo", m_gradualDecodingRefreshInfoEnabled, 0, "Control generation of gradual decoding refresh information SEI message") + ("SEINoDisplay", m_noDisplaySEITLayer, 0, "Control generation of no display SEI message\n" + "\tN: 0 < N enable no display SEI message for temporal layer N or higher\n" + "\t0: disable") + ("SEIDecodingUnitInfo", m_decodingUnitInfoSEIEnabled, 0, "Control generation of decoding unit information SEI message.") + ("SEISOPDescription", m_SOPDescriptionSEIEnabled, 0, "Control generation of SOP description SEI messages") + ("SEIScalableNesting", m_scalableNestingSEIEnabled, 0, "Control generation of scalable nesting SEI messages") + ("SEITempMotionConstrainedTileSets", m_tmctsSEIEnabled, false, "Control generation of temporal motion constrained tile sets SEI message") + ("SEITimeCodeEnabled", m_timeCodeSEIEnabled, false, "Control generation of time code information SEI message") + ("SEITimeCodeNumClockTs", m_timeCodeSEINumTs, 0, "Number of clock time sets [0..3]") + ("SEITimeCodeTimeStampFlag", cfg_timeCodeSeiTimeStampFlag, cfg_timeCodeSeiTimeStampFlag, "Time stamp flag associated to each time set") + ("SEITimeCodeFieldBasedFlag", cfg_timeCodeSeiNumUnitFieldBasedFlag, cfg_timeCodeSeiNumUnitFieldBasedFlag, "Field based flag associated to each time set") + ("SEITimeCodeCountingType", cfg_timeCodeSeiCountingType, cfg_timeCodeSeiCountingType, "Counting type associated to each time set") + ("SEITimeCodeFullTsFlag", cfg_timeCodeSeiFullTimeStampFlag, cfg_timeCodeSeiFullTimeStampFlag, "Full time stamp flag associated to each time set") + ("SEITimeCodeDiscontinuityFlag", cfg_timeCodeSeiDiscontinuityFlag, cfg_timeCodeSeiDiscontinuityFlag, "Discontinuity flag associated to each time set") + ("SEITimeCodeCntDroppedFlag", cfg_timeCodeSeiCntDroppedFlag, cfg_timeCodeSeiCntDroppedFlag, "Counter dropped flag associated to each time set") + ("SEITimeCodeNumFrames", cfg_timeCodeSeiNumberOfFrames, cfg_timeCodeSeiNumberOfFrames, "Number of frames associated to each time set") + ("SEITimeCodeSecondsValue", cfg_timeCodeSeiSecondsValue, cfg_timeCodeSeiSecondsValue, "Seconds value for each time set") + ("SEITimeCodeMinutesValue", cfg_timeCodeSeiMinutesValue, cfg_timeCodeSeiMinutesValue, "Minutes value for each time set") + ("SEITimeCodeHoursValue", cfg_timeCodeSeiHoursValue, cfg_timeCodeSeiHoursValue, "Hours value for each time set") + ("SEITimeCodeSecondsFlag", cfg_timeCodeSeiSecondsFlag, cfg_timeCodeSeiSecondsFlag, "Flag to signal seconds value presence in each time set") + ("SEITimeCodeMinutesFlag", cfg_timeCodeSeiMinutesFlag, cfg_timeCodeSeiMinutesFlag, "Flag to signal minutes value presence in each time set") + ("SEITimeCodeHoursFlag", cfg_timeCodeSeiHoursFlag, cfg_timeCodeSeiHoursFlag, "Flag to signal hours value presence in each time set") + ("SEITimeCodeOffsetLength", cfg_timeCodeSeiTimeOffsetLength, cfg_timeCodeSeiTimeOffsetLength, "Time offset length associated to each time set") + ("SEITimeCodeTimeOffset", cfg_timeCodeSeiTimeOffsetValue, cfg_timeCodeSeiTimeOffsetValue, "Time offset associated to each time set") + ("SEIKneeFunctionInfo", m_kneeSEIEnabled, false, "Control generation of Knee function SEI messages") + ("SEIKneeFunctionId", m_kneeSEIId, 0, "Specifies Id of Knee function SEI message for a given session") + ("SEIKneeFunctionCancelFlag", m_kneeSEICancelFlag, false, "Indicates that Knee function SEI message cancels the persistence or follows") + ("SEIKneeFunctionPersistenceFlag", m_kneeSEIPersistenceFlag, true, "Specifies the persistence of the Knee function SEI message") + ("SEIKneeFunctionInputDrange", m_kneeSEIInputDrange, 1000, "Specifies the peak luminance level for the input picture of Knee function SEI messages") + ("SEIKneeFunctionInputDispLuminance", m_kneeSEIInputDispLuminance, 100, "Specifies the expected display brightness for the input picture of Knee function SEI messages") + ("SEIKneeFunctionOutputDrange", m_kneeSEIOutputDrange, 4000, "Specifies the peak luminance level for the output picture of Knee function SEI messages") + ("SEIKneeFunctionOutputDispLuminance", m_kneeSEIOutputDispLuminance, 800, "Specifies the expected display brightness for the output picture of Knee function SEI messages") + ("SEIKneeFunctionNumKneePointsMinus1", m_kneeSEINumKneePointsMinus1, 2, "Specifies the number of knee points - 1") + ("SEIKneeFunctionInputKneePointValue", cfg_kneeSEIInputKneePointValue, cfg_kneeSEIInputKneePointValue, "Array of input knee point") + ("SEIKneeFunctionOutputKneePointValue", cfg_kneeSEIOutputKneePointValue, cfg_kneeSEIOutputKneePointValue, "Array of output knee point") + ("SEIMasteringDisplayColourVolume", m_masteringDisplay.colourVolumeSEIEnabled, false, "Control generation of mastering display colour volume SEI messages") + ("SEIMasteringDisplayMaxLuminance", m_masteringDisplay.maxLuminance, 10000u, "Specifies the mastering display maximum luminance value in units of 1/10000 candela per square metre (32-bit code value)") + ("SEIMasteringDisplayMinLuminance", m_masteringDisplay.minLuminance, 0u, "Specifies the mastering display minimum luminance value in units of 1/10000 candela per square metre (32-bit code value)") + ("SEIMasteringDisplayPrimaries", cfg_DisplayPrimariesCode, cfg_DisplayPrimariesCode, "Mastering display primaries for all three colour planes in CIE xy coordinates in increments of 1/50000 (results in the ranges 0 to 50000 inclusive)") + ("SEIMasteringDisplayWhitePoint", cfg_DisplayWhitePointCode, cfg_DisplayWhitePointCode, "Mastering display white point CIE xy coordinates in normalised increments of 1/50000 (e.g. 0.333 = 16667)") + ("Verbose", m_verboseLevel, 1, "verboseLeveL") + + ; + + for(Int i=1; i& argv_unhandled = po::scanArgv(opts, argc, (const Char**) argv); + + for (list::const_iterator it = argv_unhandled.begin(); it != argv_unhandled.end(); it++) + { + fprintf(stderr, "Unhandled argument ignored: `%s'\n", *it); + } + + if (argc == 1 || do_help) + { + /* argc == 1: no options have been specified */ + po::doHelp(cout, opts); + return false; + } + + /* + * Set any derived parameters + */ + /* convert std::string to c string for compatability */ + m_pchInputFile = cfg_InputFile.empty() ? NULL : strdup(cfg_InputFile.c_str()); + m_pchBitstreamFile = cfg_BitstreamFile.empty() ? NULL : strdup(cfg_BitstreamFile.c_str()); + m_pchReconFile = cfg_ReconFile.empty() ? NULL : strdup(cfg_ReconFile.c_str()); + m_pchdQPFile = cfg_dQPFile.empty() ? NULL : strdup(cfg_dQPFile.c_str()); + + if(m_isField) + { + //Frame height + m_iSourceHeightOrg = m_iSourceHeight; + //Field height + m_iSourceHeight = m_iSourceHeight >> 1; + //number of fields to encode + m_framesToBeEncoded *= 2; + } + + if( !m_tileUniformSpacingFlag && m_numTileColumnsMinus1 > 0 ) + { + if (cfg_ColumnWidth.values.size() > m_numTileColumnsMinus1) + { + printf( "The number of columns whose width are defined is larger than the allowed number of columns.\n" ); + exit( EXIT_FAILURE ); + } + else if (cfg_ColumnWidth.values.size() < m_numTileColumnsMinus1) + { + printf( "The width of some columns is not defined.\n" ); + exit( EXIT_FAILURE ); + } + else + { + m_tileColumnWidth.resize(m_numTileColumnsMinus1); + for(UInt i=0; i 0 ) + { + if (cfg_RowHeight.values.size() > m_numTileRowsMinus1) + { + printf( "The number of rows whose height are defined is larger than the allowed number of rows.\n" ); + exit( EXIT_FAILURE ); + } + else if (cfg_RowHeight.values.size() < m_numTileRowsMinus1) + { + printf( "The height of some rows is not defined.\n" ); + exit( EXIT_FAILURE ); + } + else + { + m_tileRowHeight.resize(m_numTileRowsMinus1); + for(UInt i=0; i= 1000 && extendedProfile <= 2316) + { + m_profile = Profile::MAINREXT; + if (m_bitDepthConstraint != 0 || tmpConstraintChromaFormat != 0) + { + fprintf(stderr, "Error: The bit depth and chroma format constraints are not used when an explicit RExt profile is specified\n"); + exit(EXIT_FAILURE); + } + m_bitDepthConstraint = (extendedProfile%100); + m_intraConstraintFlag = (extendedProfile>=2000); + switch ((extendedProfile/100)%10) + { + case 0: tmpConstraintChromaFormat=400; break; + case 1: tmpConstraintChromaFormat=420; break; + case 2: tmpConstraintChromaFormat=422; break; + default: tmpConstraintChromaFormat=444; break; + } + } + else + { + m_profile = Profile::Name(extendedProfile); + } + + if (m_profile == Profile::HIGHTHROUGHPUTREXT ) + { + if (m_bitDepthConstraint == 0) m_bitDepthConstraint = 16; + m_chromaFormatConstraint = (tmpConstraintChromaFormat == 0) ? CHROMA_444 : numberToChromaFormat(tmpConstraintChromaFormat); + } + else if (m_profile == Profile::MAINREXT) + { + if (m_bitDepthConstraint == 0 && tmpConstraintChromaFormat == 0) + { + // produce a valid combination, if possible. + const Bool bUsingGeneralRExtTools = m_useResidualRotation || + m_useSingleSignificanceMapContext || + m_useResidualDPCM[RDPCM_SIGNAL_IMPLICIT] || + m_useResidualDPCM[RDPCM_SIGNAL_EXPLICIT] || + !m_enableIntraReferenceSmoothing || + m_useGolombRiceParameterAdaptation || + m_transformSkipLog2MaxSize!=2; + const Bool bUsingChromaQPAdjustment= m_maxCUChromaQpAdjustmentDepth >= 0; + const Bool bUsingExtendedPrecision = m_useExtendedPrecision; + m_chromaFormatConstraint = NUM_CHROMA_FORMAT; + automaticallySelectRExtProfile(bUsingGeneralRExtTools, + bUsingChromaQPAdjustment, + bUsingExtendedPrecision, + m_intraConstraintFlag, + m_bitDepthConstraint, + m_chromaFormatConstraint, + m_chromaFormatIDC==CHROMA_400 ? m_internalBitDepth[CHANNEL_TYPE_LUMA] : std::max(m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA]), + m_chromaFormatIDC); + } + else if (m_bitDepthConstraint == 0 || tmpConstraintChromaFormat == 0) + { + fprintf(stderr, "Error: The bit depth and chroma format constraints must either both be specified or both be configured automatically\n"); + exit(EXIT_FAILURE); + } + else + { + m_chromaFormatConstraint = numberToChromaFormat(tmpConstraintChromaFormat); + } + } + else + { + m_chromaFormatConstraint = (tmpConstraintChromaFormat == 0) ? m_chromaFormatIDC : numberToChromaFormat(tmpConstraintChromaFormat); + m_bitDepthConstraint = (m_profile == Profile::MAIN10?10:8); + } + + + m_inputColourSpaceConvert = stringToInputColourSpaceConvert(inputColourSpaceConvert, true); + + switch (m_conformanceWindowMode) + { + case 0: + { + // no conformance or padding + m_confWinLeft = m_confWinRight = m_confWinTop = m_confWinBottom = 0; + m_aiPad[1] = m_aiPad[0] = 0; + break; + } + case 1: + { + // automatic padding to minimum CU size + Int minCuSize = m_uiMaxCUHeight >> (m_uiMaxCUDepth - 1); + if (m_iSourceWidth % minCuSize) + { + m_aiPad[0] = m_confWinRight = ((m_iSourceWidth / minCuSize) + 1) * minCuSize - m_iSourceWidth; + m_iSourceWidth += m_confWinRight; + } + if (m_iSourceHeight % minCuSize) + { + m_aiPad[1] = m_confWinBottom = ((m_iSourceHeight / minCuSize) + 1) * minCuSize - m_iSourceHeight; + m_iSourceHeight += m_confWinBottom; + if ( m_isField ) + { + m_iSourceHeightOrg += m_confWinBottom << 1; + m_aiPad[1] = m_confWinBottom << 1; + } + } + if (m_aiPad[0] % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0) + { + fprintf(stderr, "Error: picture width is not an integer multiple of the specified chroma subsampling\n"); + exit(EXIT_FAILURE); + } + if (m_aiPad[1] % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0) + { + fprintf(stderr, "Error: picture height is not an integer multiple of the specified chroma subsampling\n"); + exit(EXIT_FAILURE); + } + break; + } + case 2: + { + //padding + m_iSourceWidth += m_aiPad[0]; + m_iSourceHeight += m_aiPad[1]; + m_confWinRight = m_aiPad[0]; + m_confWinBottom = m_aiPad[1]; + break; + } + case 3: + { + // conformance + if ((m_confWinLeft == 0) && (m_confWinRight == 0) && (m_confWinTop == 0) && (m_confWinBottom == 0)) + { + fprintf(stderr, "Warning: Conformance window enabled, but all conformance window parameters set to zero\n"); + } + if ((m_aiPad[1] != 0) || (m_aiPad[0]!=0)) + { + fprintf(stderr, "Warning: Conformance window enabled, padding parameters will be ignored\n"); + } + m_aiPad[1] = m_aiPad[0] = 0; + break; + } + } + + // allocate slice-based dQP values + m_aidQP = new Int[ m_framesToBeEncoded + m_iGOPSize + 1 ]; + ::memset( m_aidQP, 0, sizeof(Int)*( m_framesToBeEncoded + m_iGOPSize + 1 ) ); + + // handling of floating-point QP values + // if QP is not integer, sequence is split into two sections having QP and QP+1 + m_iQP = (Int)( m_fQP ); + if ( m_iQP < m_fQP ) + { + Int iSwitchPOC = (Int)( m_framesToBeEncoded - (m_fQP - m_iQP)*m_framesToBeEncoded + 0.5 ); + + iSwitchPOC = (Int)( (Double)iSwitchPOC / m_iGOPSize + 0.5 )*m_iGOPSize; + for ( Int i=iSwitchPOC; i10) + { + m_saoOffsetBitShift[ch]=UInt(Clip3(0, m_internalBitDepth[ch]-10, Int(m_internalBitDepth[ch]-10 + 0.165*m_iQP - 3.22 + 0.5) ) ); + } + else + { + m_saoOffsetBitShift[ch]=0; + } + } + else + { + m_saoOffsetBitShift[ch]=UInt(saoOffsetBitShift[ch]); + } + } + + // reading external dQP description from file + if ( m_pchdQPFile ) + { + FILE* fpt=fopen( m_pchdQPFile, "r" ); + if ( fpt ) + { + Int iValue; + Int iPOC = 0; + while ( iPOC < m_framesToBeEncoded ) + { + if ( fscanf(fpt, "%d", &iValue ) == EOF ) break; + m_aidQP[ iPOC ] = iValue; + iPOC++; + } + fclose(fpt); + } + } + m_iWaveFrontSubstreams = m_iWaveFrontSynchro ? (m_iSourceHeight + m_uiMaxCUHeight - 1) / m_uiMaxCUHeight : 1; + + if( m_masteringDisplay.colourVolumeSEIEnabled ) + { + for(UInt idx=0; idx<6; idx++) + { + m_masteringDisplay.primaries[idx/2][idx%2] = UShort((cfg_DisplayPrimariesCode.values.size() > idx) ? cfg_DisplayPrimariesCode.values[idx] : 0); + } + for(UInt idx=0; idx<2; idx++) + { + m_masteringDisplay.whitePoint[idx] = UShort((cfg_DisplayWhitePointCode.values.size() > idx) ? cfg_DisplayWhitePointCode.values[idx] : 0); + } + } + + if( m_toneMappingInfoSEIEnabled && !m_toneMapCancelFlag ) + { + if( m_toneMapModelId == 2 && !cfg_startOfCodedInterval.values.empty() ) + { + const UInt num = 1u<< m_toneMapTargetBitDepth; + m_startOfCodedInterval = new Int[num]; + for(UInt i=0; i i ? cfg_startOfCodedInterval.values[i] : 0; + } + } + else + { + m_startOfCodedInterval = NULL; + } + if( ( m_toneMapModelId == 3 ) && ( m_numPivots > 0 ) ) + { + if( !cfg_codedPivotValue.values.empty() && !cfg_targetPivotValue.values.empty() ) + { + m_codedPivotValue = new Int[m_numPivots]; + m_targetPivotValue = new Int[m_numPivots]; + for(UInt i=0; i i ? cfg_codedPivotValue.values [i] : 0; + m_targetPivotValue[i] = cfg_targetPivotValue.values.size() > i ? cfg_targetPivotValue.values[i] : 0; + } + } + } + else + { + m_codedPivotValue = NULL; + m_targetPivotValue = NULL; + } + } + + if( m_kneeSEIEnabled && !m_kneeSEICancelFlag ) + { + assert ( m_kneeSEINumKneePointsMinus1 >= 0 && m_kneeSEINumKneePointsMinus1 < 999 ); + m_kneeSEIInputKneePoint = new Int[m_kneeSEINumKneePointsMinus1+1]; + m_kneeSEIOutputKneePoint = new Int[m_kneeSEINumKneePointsMinus1+1]; + for(Int i=0; i<(m_kneeSEINumKneePointsMinus1+1); i++) + { + m_kneeSEIInputKneePoint[i] = cfg_kneeSEIInputKneePointValue.values.size() > i ? cfg_kneeSEIInputKneePointValue.values[i] : 1; + m_kneeSEIOutputKneePoint[i] = cfg_kneeSEIOutputKneePointValue.values.size() > i ? cfg_kneeSEIOutputKneePointValue.values[i] : 0; + } + } + + if(m_timeCodeSEIEnabled) + { + for(Int i = 0; i < m_timeCodeSEINumTs && i < MAX_TIMECODE_SEI_SETS; i++) + { + m_timeSetArray[i].clockTimeStampFlag = cfg_timeCodeSeiTimeStampFlag .values.size()>i ? cfg_timeCodeSeiTimeStampFlag .values [i] : false; + m_timeSetArray[i].numUnitFieldBasedFlag = cfg_timeCodeSeiNumUnitFieldBasedFlag.values.size()>i ? cfg_timeCodeSeiNumUnitFieldBasedFlag.values [i] : 0; + m_timeSetArray[i].countingType = cfg_timeCodeSeiCountingType .values.size()>i ? cfg_timeCodeSeiCountingType .values [i] : 0; + m_timeSetArray[i].fullTimeStampFlag = cfg_timeCodeSeiFullTimeStampFlag .values.size()>i ? cfg_timeCodeSeiFullTimeStampFlag .values [i] : 0; + m_timeSetArray[i].discontinuityFlag = cfg_timeCodeSeiDiscontinuityFlag .values.size()>i ? cfg_timeCodeSeiDiscontinuityFlag .values [i] : 0; + m_timeSetArray[i].cntDroppedFlag = cfg_timeCodeSeiCntDroppedFlag .values.size()>i ? cfg_timeCodeSeiCntDroppedFlag .values [i] : 0; + m_timeSetArray[i].numberOfFrames = cfg_timeCodeSeiNumberOfFrames .values.size()>i ? cfg_timeCodeSeiNumberOfFrames .values [i] : 0; + m_timeSetArray[i].secondsValue = cfg_timeCodeSeiSecondsValue .values.size()>i ? cfg_timeCodeSeiSecondsValue .values [i] : 0; + m_timeSetArray[i].minutesValue = cfg_timeCodeSeiMinutesValue .values.size()>i ? cfg_timeCodeSeiMinutesValue .values [i] : 0; + m_timeSetArray[i].hoursValue = cfg_timeCodeSeiHoursValue .values.size()>i ? cfg_timeCodeSeiHoursValue .values [i] : 0; + m_timeSetArray[i].secondsFlag = cfg_timeCodeSeiSecondsFlag .values.size()>i ? cfg_timeCodeSeiSecondsFlag .values [i] : 0; + m_timeSetArray[i].minutesFlag = cfg_timeCodeSeiMinutesFlag .values.size()>i ? cfg_timeCodeSeiMinutesFlag .values [i] : 0; + m_timeSetArray[i].hoursFlag = cfg_timeCodeSeiHoursFlag .values.size()>i ? cfg_timeCodeSeiHoursFlag .values [i] : 0; + m_timeSetArray[i].timeOffsetLength = cfg_timeCodeSeiTimeOffsetLength .values.size()>i ? cfg_timeCodeSeiTimeOffsetLength .values [i] : 0; + m_timeSetArray[i].timeOffsetValue = cfg_timeCodeSeiTimeOffsetValue .values.size()>i ? cfg_timeCodeSeiTimeOffsetValue .values [i] : 0; + } + } + + // check validity of input parameters + xCheckParameter(); + + // set global varibles + xSetGlobal(); + + // print-out parameters + if (m_verboseLevel) { + xPrintParameter(); + } + + return true; +} + + +// ==================================================================================================================== +// Private member functions +// ==================================================================================================================== + +Void TAppEncCfg::xCheckParameter() +{ + if (!m_decodedPictureHashSEIEnabled && 0) + { + fprintf(stderr, "******************************************************************\n"); + fprintf(stderr, "** WARNING: --SEIDecodedPictureHash is now disabled by default. **\n"); + fprintf(stderr, "** Automatic verification of decoded pictures by a **\n"); + fprintf(stderr, "** decoder requires this option to be enabled. **\n"); + fprintf(stderr, "******************************************************************\n"); + } + if( m_profile==Profile::NONE && 0) + { + fprintf(stderr, "***************************************************************************\n"); + fprintf(stderr, "** WARNING: For conforming bitstreams a valid Profile value must be set! **\n"); + fprintf(stderr, "***************************************************************************\n"); + } + if( m_level==Level::NONE && 0) + { + fprintf(stderr, "***************************************************************************\n"); + fprintf(stderr, "** WARNING: For conforming bitstreams a valid Level value must be set! **\n"); + fprintf(stderr, "***************************************************************************\n"); + } + + Bool check_failed = false; /* abort if there is a fatal configuration problem */ +#define xConfirmPara(a,b) check_failed |= confirmPara(a,b) + + const UInt maxBitDepth=(m_chromaFormatIDC==CHROMA_400) ? m_internalBitDepth[CHANNEL_TYPE_LUMA] : std::max(m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA]); + xConfirmPara(m_bitDepthConstraint 3 || chromaFormatIdx>3) ? false : (validRExtProfileNames[intraIdx][bitDepthIdx][chromaFormatIdx] != NONE); + xConfirmPara(!bValidProfile, "Invalid intra constraint flag, bit depth constraint flag and chroma format constraint flag combination for a RExt profile"); + const Bool bUsingGeneralRExtTools = m_useResidualRotation || + m_useSingleSignificanceMapContext || + m_useResidualDPCM[RDPCM_SIGNAL_IMPLICIT] || + m_useResidualDPCM[RDPCM_SIGNAL_EXPLICIT] || + !m_enableIntraReferenceSmoothing || + m_useGolombRiceParameterAdaptation || + m_transformSkipLog2MaxSize!=2; + const Bool bUsingChromaQPTool = m_maxCUChromaQpAdjustmentDepth >= 0; + const Bool bUsingExtendedPrecision = m_useExtendedPrecision; + + xConfirmPara((m_chromaFormatConstraint==CHROMA_420 || m_chromaFormatConstraint==CHROMA_400) && bUsingChromaQPTool, "CU Chroma QP adjustment cannot be used for 4:0:0 or 4:2:0 RExt profiles"); + xConfirmPara(m_bitDepthConstraint != 16 && bUsingExtendedPrecision, "Extended precision can only be used in 16-bit RExt profiles"); + if (!(m_chromaFormatConstraint == CHROMA_400 && m_bitDepthConstraint == 16) && m_chromaFormatConstraint!=CHROMA_444) + { + xConfirmPara(bUsingGeneralRExtTools, "Combination of tools and profiles are not possible in the specified RExt profile."); + } + if (!m_intraConstraintFlag && m_bitDepthConstraint==16 && m_chromaFormatConstraint==CHROMA_444) + { + fprintf(stderr, "********************************************************************************************************\n"); + fprintf(stderr, "** WARNING: The RExt constraint flags describe a non standard combination (used for development only) **\n"); + fprintf(stderr, "********************************************************************************************************\n"); + } + } + else + { + xConfirmPara( m_chromaFormatConstraint != CHROMA_444, "chroma format constraint must be 4:4:4 in the High Throughput 4:4:4 16-bit Intra profile."); + xConfirmPara( m_bitDepthConstraint != 16, "bit depth constraint must be 4:4:4 in the High Throughput 4:4:4 16-bit Intra profile."); + xConfirmPara( m_intraConstraintFlag != 1, "intra constraint flag must be 1 in the High Throughput 4:4:4 16-bit Intra profile."); + } + } + else + { + xConfirmPara(m_bitDepthConstraint!=((m_profile==Profile::MAIN10)?10:8), "BitDepthConstraint must be 8 for MAIN profile and 10 for MAIN10 profile."); + xConfirmPara(m_chromaFormatConstraint!=CHROMA_420, "ChromaFormatConstraint must be 420 for non main-RExt profiles."); + xConfirmPara(m_intraConstraintFlag==true, "IntraConstraintFlag must be false for non main_RExt profiles."); + xConfirmPara(m_lowerBitRateConstraintFlag==false, "LowerBitrateConstraintFlag must be true for non main-RExt profiles."); + + xConfirmPara(m_useCrossComponentPrediction==true, "CrossComponentPrediction must not be used for non main-RExt profiles."); + xConfirmPara(m_transformSkipLog2MaxSize!=2, "Transform Skip Log2 Max Size must be 2 for V1 profiles."); + xConfirmPara(m_useResidualRotation==true, "UseResidualRotation must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useSingleSignificanceMapContext==true, "UseSingleSignificanceMapContext must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useResidualDPCM[RDPCM_SIGNAL_IMPLICIT]==true, "ImplicitResidualDPCM must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useResidualDPCM[RDPCM_SIGNAL_EXPLICIT]==true, "ExplicitResidualDPCM must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useGolombRiceParameterAdaptation==true, "GolombRiceParameterAdaption must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useExtendedPrecision==true, "UseExtendedPrecision must not be enabled for non main-RExt profiles."); + xConfirmPara(m_useHighPrecisionPredictionWeighting==true, "UseHighPrecisionPredictionWeighting must not be enabled for non main-RExt profiles."); + xConfirmPara(m_enableIntraReferenceSmoothing==false, "EnableIntraReferenceSmoothing must be enabled for non main-RExt profiles."); + xConfirmPara(m_alignCABACBeforeBypass, "AlignCABACBeforeBypass cannot be enabled for non main-RExt profiles."); + } + + // check range of parameters + xConfirmPara( m_inputBitDepth[CHANNEL_TYPE_LUMA ] < 8, "InputBitDepth must be at least 8" ); + xConfirmPara( m_inputBitDepth[CHANNEL_TYPE_CHROMA] < 8, "InputBitDepthC must be at least 8" ); + +#if !RExt__HIGH_BIT_DEPTH_SUPPORT + if (m_useExtendedPrecision) + { + for (UInt channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + xConfirmPara((m_internalBitDepth[channelType] > 8) , "Model is not configured to support high enough internal accuracies - enable RExt__HIGH_BIT_DEPTH_SUPPORT to use increased precision internal data types etc..."); + } + } + else + { + for (UInt channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + xConfirmPara((m_internalBitDepth[channelType] > 12) , "Model is not configured to support high enough internal accuracies - enable RExt__HIGH_BIT_DEPTH_SUPPORT to use increased precision internal data types etc..."); + } + } +#endif + + xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA ] < m_inputBitDepth[CHANNEL_TYPE_LUMA ]), "MSB-extended bit depth for luma channel (--MSBExtendedBitDepth) must be greater than or equal to input bit depth for luma channel (--InputBitDepth)" ); + xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] < m_inputBitDepth[CHANNEL_TYPE_CHROMA]), "MSB-extended bit depth for chroma channel (--MSBExtendedBitDepthC) must be greater than or equal to input bit depth for chroma channel (--InputBitDepthC)" ); + + xConfirmPara( m_saoOffsetBitShift[CHANNEL_TYPE_LUMA] > (m_internalBitDepth[CHANNEL_TYPE_LUMA ]<10?0:(m_internalBitDepth[CHANNEL_TYPE_LUMA ]-10)), "SaoLumaOffsetBitShift must be in the range of 0 to InternalBitDepth-10, inclusive"); + xConfirmPara( m_saoOffsetBitShift[CHANNEL_TYPE_CHROMA] > (m_internalBitDepth[CHANNEL_TYPE_CHROMA]<10?0:(m_internalBitDepth[CHANNEL_TYPE_CHROMA]-10)), "SaoChromaOffsetBitShift must be in the range of 0 to InternalBitDepthC-10, inclusive"); + + xConfirmPara( m_chromaFormatIDC >= NUM_CHROMA_FORMAT, "ChromaFormatIDC must be either 400, 420, 422 or 444" ); + std::string sTempIPCSC="InputColourSpaceConvert must be empty, "+getListOfColourSpaceConverts(true); + xConfirmPara( m_inputColourSpaceConvert >= NUMBER_INPUT_COLOUR_SPACE_CONVERSIONS, sTempIPCSC.c_str() ); + xConfirmPara( m_InputChromaFormatIDC >= NUM_CHROMA_FORMAT, "InputChromaFormatIDC must be either 400, 420, 422 or 444" ); + xConfirmPara( m_iFrameRate <= 0, "Frame rate must be more than 1" ); + xConfirmPara( m_framesToBeEncoded <= 0, "Total Number Of Frames encoded must be more than 0" ); + xConfirmPara( m_iGOPSize < 1 , "GOP Size must be greater or equal to 1" ); + xConfirmPara( m_iGOPSize > 1 && m_iGOPSize % 2, "GOP Size must be a multiple of 2, if GOP Size is greater than 1" ); + xConfirmPara( (m_iIntraPeriod > 0 && m_iIntraPeriod < m_iGOPSize) || m_iIntraPeriod == 0, "Intra period must be more than GOP size, or -1 , not 0" ); +#if ALLOW_RECOVERY_POINT_AS_RAP + xConfirmPara( m_iDecodingRefreshType < 0 || m_iDecodingRefreshType > 3, "Decoding Refresh Type must be comprised between 0 and 3 included" ); + if(m_iDecodingRefreshType == 3) + { + xConfirmPara( !m_recoveryPointSEIEnabled, "When using RecoveryPointSEI messages as RA points, recoveryPointSEI must be enabled" ); + } +#else + xConfirmPara( m_iDecodingRefreshType < 0 || m_iDecodingRefreshType > 2, "Decoding Refresh Type must be equal to 0, 1 or 2" ); +#endif + + if (m_isField) + { + if (!m_pictureTimingSEIEnabled) + { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "** WARNING: Picture Timing SEI should be enabled for field coding! **\n"); + fprintf(stderr, "****************************************************************************\n"); + } + } + if ( m_bufferingPeriodSEIEnabled && !m_activeParameterSetsSEIEnabled) + { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "** WARNING: using buffering period SEI requires SPS activation with **\n"); + fprintf(stderr, "** active parameter sets SEI. Enabling active parameter sets SEI **\n"); + fprintf(stderr, "****************************************************************************\n"); + m_activeParameterSetsSEIEnabled = 1; + } + if ( m_pictureTimingSEIEnabled && !m_activeParameterSetsSEIEnabled) + { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "** WARNING: using picture timing SEI requires SPS activation with active **\n"); + fprintf(stderr, "** parameter sets SEI. Enabling active parameter sets SEI. **\n"); + fprintf(stderr, "****************************************************************************\n"); + m_activeParameterSetsSEIEnabled = 1; + } + + if(m_useCrossComponentPrediction && (m_chromaFormatIDC != CHROMA_444)) + { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "** WARNING: Cross-component prediction is specified for 4:4:4 format only **\n"); + fprintf(stderr, "****************************************************************************\n"); + + m_useCrossComponentPrediction = false; + } + + if ( m_CUTransquantBypassFlagForce && m_bUseHADME) + { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "** WARNING: --HadamardME has been disabled due to the enabling of **\n"); + fprintf(stderr, "** --CUTransquantBypassFlagForce **\n"); + fprintf(stderr, "****************************************************************************\n"); + m_bUseHADME = false; // this has been disabled so that the lambda is calculated slightly differently for lossless modes (as a result of JCTVC-R0104). + } + + xConfirmPara (m_transformSkipLog2MaxSize < 2, "Transform Skip Log2 Max Size must be at least 2 (4x4)"); + + if (m_transformSkipLog2MaxSize!=2 && m_useTransformSkipFast) + { + fprintf(stderr, "***************************************************************************\n"); + fprintf(stderr, "** WARNING: Transform skip fast is enabled (which only tests NxN splits),**\n"); + fprintf(stderr, "** but transform skip log2 max size is not 2 (4x4) **\n"); + fprintf(stderr, "** It may be better to disable transform skip fast mode **\n"); + fprintf(stderr, "***************************************************************************\n"); + } + + xConfirmPara( m_iQP < -6 * (m_internalBitDepth[CHANNEL_TYPE_LUMA] - 8) || m_iQP > 51, "QP exceeds supported range (-QpBDOffsety to 51)" ); + xConfirmPara( m_loopFilterBetaOffsetDiv2 < -6 || m_loopFilterBetaOffsetDiv2 > 6, "Loop Filter Beta Offset div. 2 exceeds supported range (-6 to 6)"); + xConfirmPara( m_loopFilterTcOffsetDiv2 < -6 || m_loopFilterTcOffsetDiv2 > 6, "Loop Filter Tc Offset div. 2 exceeds supported range (-6 to 6)"); + xConfirmPara( m_iFastSearch < 0 || m_iFastSearch > 2, "Fast Search Mode is not supported value (0:Full search 1:Diamond 2:PMVFAST)" ); + xConfirmPara( m_iSearchRange < 0 , "Search Range must be more than 0" ); + xConfirmPara( m_bipredSearchRange < 0 , "Search Range must be more than 0" ); + xConfirmPara( m_iMaxDeltaQP > 7, "Absolute Delta QP exceeds supported range (0 to 7)" ); + xConfirmPara( m_iMaxCuDQPDepth > m_uiMaxCUDepth - 1, "Absolute depth for a minimum CuDQP exceeds maximum coding unit depth" ); + + xConfirmPara( m_cbQpOffset < -12, "Min. Chroma Cb QP Offset is -12" ); + xConfirmPara( m_cbQpOffset > 12, "Max. Chroma Cb QP Offset is 12" ); + xConfirmPara( m_crQpOffset < -12, "Min. Chroma Cr QP Offset is -12" ); + xConfirmPara( m_crQpOffset > 12, "Max. Chroma Cr QP Offset is 12" ); + + xConfirmPara( m_iQPAdaptationRange <= 0, "QP Adaptation Range must be more than 0" ); + if (m_iDecodingRefreshType == 2) + { + xConfirmPara( m_iIntraPeriod > 0 && m_iIntraPeriod <= m_iGOPSize , "Intra period must be larger than GOP size for periodic IDR pictures"); + } + xConfirmPara( (m_uiMaxCUWidth >> m_uiMaxCUDepth) < 4, "Minimum partition width size should be larger than or equal to 8"); + xConfirmPara( (m_uiMaxCUHeight >> m_uiMaxCUDepth) < 4, "Minimum partition height size should be larger than or equal to 8"); + xConfirmPara( m_uiMaxCUWidth < 16, "Maximum partition width size should be larger than or equal to 16"); + xConfirmPara( m_uiMaxCUHeight < 16, "Maximum partition height size should be larger than or equal to 16"); + xConfirmPara( (m_iSourceWidth % (m_uiMaxCUWidth >> (m_uiMaxCUDepth-1)))!=0, "Resulting coded frame width must be a multiple of the minimum CU size"); + xConfirmPara( (m_iSourceHeight % (m_uiMaxCUHeight >> (m_uiMaxCUDepth-1)))!=0, "Resulting coded frame height must be a multiple of the minimum CU size"); + + xConfirmPara( m_uiQuadtreeTULog2MinSize < 2, "QuadtreeTULog2MinSize must be 2 or greater."); + xConfirmPara( m_uiQuadtreeTULog2MaxSize > 5, "QuadtreeTULog2MaxSize must be 5 or smaller."); + xConfirmPara( m_uiQuadtreeTULog2MaxSize < m_uiQuadtreeTULog2MinSize, "QuadtreeTULog2MaxSize must be greater than or equal to m_uiQuadtreeTULog2MinSize."); + xConfirmPara( (1< m_uiMaxCUWidth, "QuadtreeTULog2MaxSize must be log2(maxCUSize) or smaller."); + xConfirmPara( ( 1 << m_uiQuadtreeTULog2MinSize ) >= ( m_uiMaxCUWidth >> (m_uiMaxCUDepth-1)), "QuadtreeTULog2MinSize must not be greater than or equal to minimum CU size" ); + xConfirmPara( ( 1 << m_uiQuadtreeTULog2MinSize ) >= ( m_uiMaxCUHeight >> (m_uiMaxCUDepth-1)), "QuadtreeTULog2MinSize must not be greater than or equal to minimum CU size" ); + xConfirmPara( m_uiQuadtreeTUMaxDepthInter < 1, "QuadtreeTUMaxDepthInter must be greater than or equal to 1" ); + xConfirmPara( m_uiMaxCUWidth < ( 1 << (m_uiQuadtreeTULog2MinSize + m_uiQuadtreeTUMaxDepthInter - 1) ), "QuadtreeTUMaxDepthInter must be less than or equal to the difference between log2(maxCUSize) and QuadtreeTULog2MinSize plus 1" ); + xConfirmPara( m_uiQuadtreeTUMaxDepthIntra < 1, "QuadtreeTUMaxDepthIntra must be greater than or equal to 1" ); + xConfirmPara( m_uiMaxCUWidth < ( 1 << (m_uiQuadtreeTULog2MinSize + m_uiQuadtreeTUMaxDepthIntra - 1) ), "QuadtreeTUMaxDepthInter must be less than or equal to the difference between log2(maxCUSize) and QuadtreeTULog2MinSize plus 1" ); + + xConfirmPara( m_maxNumMergeCand < 1, "MaxNumMergeCand must be 1 or greater."); + xConfirmPara( m_maxNumMergeCand > 5, "MaxNumMergeCand must be 5 or smaller."); + +#if ADAPTIVE_QP_SELECTION + xConfirmPara( m_bUseAdaptQpSelect == true && m_iQP < 0, "AdaptiveQpSelection must be disabled when QP < 0."); + xConfirmPara( m_bUseAdaptQpSelect == true && (m_cbQpOffset !=0 || m_crQpOffset != 0 ), "AdaptiveQpSelection must be disabled when ChromaQpOffset is not equal to 0."); +#endif + + if( m_usePCM) + { + for (UInt channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + xConfirmPara(((m_MSBExtendedBitDepth[channelType] > m_internalBitDepth[channelType]) && m_bPCMInputBitDepthFlag), "PCM bit depth cannot be greater than internal bit depth (PCMInputBitDepthFlag cannot be used when InputBitDepth or MSBExtendedBitDepth > InternalBitDepth)"); + } + xConfirmPara( m_uiPCMLog2MinSize < 3, "PCMLog2MinSize must be 3 or greater."); + xConfirmPara( m_uiPCMLog2MinSize > 5, "PCMLog2MinSize must be 5 or smaller."); + xConfirmPara( m_pcmLog2MaxSize > 5, "PCMLog2MaxSize must be 5 or smaller."); + xConfirmPara( m_pcmLog2MaxSize < m_uiPCMLog2MinSize, "PCMLog2MaxSize must be equal to or greater than m_uiPCMLog2MinSize."); + } + + xConfirmPara( m_sliceMode < 0 || m_sliceMode > 3, "SliceMode exceeds supported range (0 to 3)" ); + if (m_sliceMode!=0) + { + xConfirmPara( m_sliceArgument < 1 , "SliceArgument should be larger than or equal to 1" ); + } + xConfirmPara( m_sliceSegmentMode < 0 || m_sliceSegmentMode > 3, "SliceSegmentMode exceeds supported range (0 to 3)" ); + if (m_sliceSegmentMode!=0) + { + xConfirmPara( m_sliceSegmentArgument < 1 , "SliceSegmentArgument should be larger than or equal to 1" ); + } + + Bool tileFlag = (m_numTileColumnsMinus1 > 0 || m_numTileRowsMinus1 > 0 ); + if (m_profile!=Profile::HIGHTHROUGHPUTREXT) + { + xConfirmPara( tileFlag && m_iWaveFrontSynchro, "Tile and Wavefront can not be applied together, except in the High Throughput Intra 4:4:4 16 profile"); + } + + xConfirmPara( m_iSourceWidth % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_iSourceHeight % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Picture height must be an integer multiple of the specified chroma subsampling"); + + xConfirmPara( m_aiPad[0] % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Horizontal padding must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_aiPad[1] % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Vertical padding must be an integer multiple of the specified chroma subsampling"); + + xConfirmPara( m_confWinLeft % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Left conformance window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_confWinRight % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Right conformance window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_confWinTop % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Top conformance window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_confWinBottom % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Bottom conformance window offset must be an integer multiple of the specified chroma subsampling"); + + xConfirmPara( m_defaultDisplayWindowFlag && !m_vuiParametersPresentFlag, "VUI needs to be enabled for default display window"); + + if (m_defaultDisplayWindowFlag) + { + xConfirmPara( m_defDispWinLeftOffset % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Left default display window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_defDispWinRightOffset % TComSPS::getWinUnitX(m_chromaFormatIDC) != 0, "Right default display window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_defDispWinTopOffset % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Top default display window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara( m_defDispWinBottomOffset % TComSPS::getWinUnitY(m_chromaFormatIDC) != 0, "Bottom default display window offset must be an integer multiple of the specified chroma subsampling"); + } + + // max CU width and height should be power of 2 + UInt ui = m_uiMaxCUWidth; + while(ui) + { + ui >>= 1; + if( (ui & 1) == 1) + xConfirmPara( ui != 1 , "Width should be 2^n"); + } + ui = m_uiMaxCUHeight; + while(ui) + { + ui >>= 1; + if( (ui & 1) == 1) + xConfirmPara( ui != 1 , "Height should be 2^n"); + } + + /* if this is an intra-only sequence, ie IntraPeriod=1, don't verify the GOP structure + * This permits the ability to omit a GOP structure specification */ + if (m_iIntraPeriod == 1 && m_GOPList[0].m_POC == -1) + { + m_GOPList[0] = GOPEntry(); + m_GOPList[0].m_QPFactor = 1; + m_GOPList[0].m_betaOffsetDiv2 = 0; + m_GOPList[0].m_tcOffsetDiv2 = 0; + m_GOPList[0].m_POC = 1; + m_GOPList[0].m_numRefPicsActive = 4; + } + else + { + xConfirmPara( m_intraConstraintFlag, "IntraConstraintFlag cannot be 1 for inter sequences"); + } + + Bool verifiedGOP=false; + Bool errorGOP=false; + Int checkGOP=1; + Int numRefs = m_isField ? 2 : 1; + Int refList[MAX_NUM_REF_PICS+1]; + refList[0]=0; + if(m_isField) + { + refList[1] = 1; + } + Bool isOK[MAX_GOP]; + for(Int i=0; i=0&&(m_iIntraPeriod%m_iGOPSize!=0), "Intra period must be a multiple of GOPSize, or -1" ); + + for(Int i=0; i 6, "Loop Filter Beta Offset div. 2 for one of the GOP entries exceeds supported range (-6 to 6)" ); + xConfirmPara( (m_GOPList[i].m_tcOffsetDiv2 + m_loopFilterTcOffsetDiv2) < -6 || (m_GOPList[i].m_tcOffsetDiv2 + m_loopFilterTcOffsetDiv2) > 6, "Loop Filter Tc Offset div. 2 for one of the GOP entries exceeds supported range (-6 to 6)" ); + } + } + + m_extraRPSs=0; + //start looping through frames in coding order until we can verify that the GOP structure is correct. + while(!verifiedGOP&&!errorGOP) + { + Int curGOP = (checkGOP-1)%m_iGOPSize; + Int curPOC = ((checkGOP-1)/m_iGOPSize)*m_iGOPSize + m_GOPList[curGOP].m_POC; + if(m_GOPList[curGOP].m_POC<0) + { + printf("\nError: found fewer Reference Picture Sets than GOPSize\n"); + errorGOP=true; + } + else + { + //check that all reference pictures are available, or have a POC < 0 meaning they might be available in the next GOP. + Bool beforeI = false; + for(Int i = 0; i< m_GOPList[curGOP].m_numRefPics; i++) + { + Int absPOC = curPOC+m_GOPList[curGOP].m_referencePics[i]; + if(absPOC < 0) + { + beforeI=true; + } + else + { + Bool found=false; + for(Int j=0; j 0) + m_GOPList[m_iGOPSize+m_extraRPSs]=m_GOPList[curGOP]; + Int newRefs=0; + for(Int i = 0; i< m_GOPList[curGOP].m_numRefPics; i++) + { + Int absPOC = curPOC+m_GOPList[curGOP].m_referencePics[i]; + if(absPOC>=0) + { + m_GOPList[m_iGOPSize+m_extraRPSs].m_referencePics[newRefs]=m_GOPList[curGOP].m_referencePics[i]; + m_GOPList[m_iGOPSize+m_extraRPSs].m_usedByCurrPic[newRefs]=m_GOPList[curGOP].m_usedByCurrPic[i]; + newRefs++; + } + } + Int numPrefRefs = m_GOPList[curGOP].m_numRefPicsActive; + + for(Int offset = -1; offset>-checkGOP; offset--) + { + //step backwards in coding order and include any extra available pictures we might find useful to replace the ones with POC < 0. + Int offGOP = (checkGOP-1+offset)%m_iGOPSize; + Int offPOC = ((checkGOP-1+offset)/m_iGOPSize)*m_iGOPSize + m_GOPList[offGOP].m_POC; + if(offPOC>=0&&m_GOPList[offGOP].m_temporalId<=m_GOPList[curGOP].m_temporalId) + { + Bool newRef=false; + for(Int i=0; i0) + { + insertPoint = j; + break; + } + } + Int prev = offPOC-curPOC; + Int prevUsed = m_GOPList[offGOP].m_temporalId<=m_GOPList[curGOP].m_temporalId; + for(Int j=insertPoint; j=numPrefRefs) + { + break; + } + } + m_GOPList[m_iGOPSize+m_extraRPSs].m_numRefPics=newRefs; + m_GOPList[m_iGOPSize+m_extraRPSs].m_POC = curPOC; + if (m_extraRPSs == 0) + { + m_GOPList[m_iGOPSize+m_extraRPSs].m_interRPSPrediction = 0; + m_GOPList[m_iGOPSize+m_extraRPSs].m_numRefIdc = 0; + } + else + { + Int rIdx = m_iGOPSize + m_extraRPSs - 1; + Int refPOC = m_GOPList[rIdx].m_POC; + Int refPics = m_GOPList[rIdx].m_numRefPics; + Int newIdc=0; + for(Int i = 0; i<= refPics; i++) + { + Int deltaPOC = ((i != refPics)? m_GOPList[rIdx].m_referencePics[i] : 0); // check if the reference abs POC is >= 0 + Int absPOCref = refPOC+deltaPOC; + Int refIdc = 0; + for (Int j = 0; j < m_GOPList[m_iGOPSize+m_extraRPSs].m_numRefPics; j++) + { + if ( (absPOCref - curPOC) == m_GOPList[m_iGOPSize+m_extraRPSs].m_referencePics[j]) + { + if (m_GOPList[m_iGOPSize+m_extraRPSs].m_usedByCurrPic[j]) + { + refIdc = 1; + } + else + { + refIdc = 2; + } + } + } + m_GOPList[m_iGOPSize+m_extraRPSs].m_refIdc[newIdc]=refIdc; + newIdc++; + } + m_GOPList[m_iGOPSize+m_extraRPSs].m_interRPSPrediction = 1; + m_GOPList[m_iGOPSize+m_extraRPSs].m_numRefIdc = newIdc; + m_GOPList[m_iGOPSize+m_extraRPSs].m_deltaRPS = refPOC - m_GOPList[m_iGOPSize+m_extraRPSs].m_POC; + } + curGOP=m_iGOPSize+m_extraRPSs; + m_extraRPSs++; + } + numRefs=0; + for(Int i = 0; i< m_GOPList[curGOP].m_numRefPics; i++) + { + Int absPOC = curPOC+m_GOPList[curGOP].m_referencePics[i]; + if(absPOC >= 0) + { + refList[numRefs]=absPOC; + numRefs++; + } + } + refList[numRefs]=curPOC; + numRefs++; + } + checkGOP++; + } + xConfirmPara(errorGOP,"Invalid GOP structure given"); + m_maxTempLayer = 1; + for(Int i=0; i= m_maxTempLayer) + { + m_maxTempLayer = m_GOPList[i].m_temporalId+1; + } + xConfirmPara(m_GOPList[i].m_sliceType!='B' && m_GOPList[i].m_sliceType!='P' && m_GOPList[i].m_sliceType!='I', "Slice type must be equal to B or P or I"); + } + for(Int i=0; i m_maxDecPicBuffering[m_GOPList[i].m_temporalId]) + { + m_maxDecPicBuffering[m_GOPList[i].m_temporalId] = m_GOPList[i].m_numRefPics + 1; + } + Int highestDecodingNumberWithLowerPOC = 0; + for(Int j=0; j m_GOPList[i].m_POC) + { + numReorder++; + } + } + if(numReorder > m_numReorderPics[m_GOPList[i].m_temporalId]) + { + m_numReorderPics[m_GOPList[i].m_temporalId] = numReorder; + } + } + for(Int i=0; i m_maxDecPicBuffering[i] - 1) + { + m_maxDecPicBuffering[i] = m_numReorderPics[i] + 1; + } + // a lower layer can not have higher value of m_uiMaxDecPicBuffering than a higher layer + if(m_maxDecPicBuffering[i+1] < m_maxDecPicBuffering[i]) + { + m_maxDecPicBuffering[i+1] = m_maxDecPicBuffering[i]; + } + } + + // the value of num_reorder_pics[ i ] shall be in the range of 0 to max_dec_pic_buffering[ i ] - 1, inclusive + if(m_numReorderPics[MAX_TLAYER-1] > m_maxDecPicBuffering[MAX_TLAYER-1] - 1) + { + m_maxDecPicBuffering[MAX_TLAYER-1] = m_numReorderPics[MAX_TLAYER-1] + 1; + } + + if(m_vuiParametersPresentFlag && m_bitstreamRestrictionFlag) + { + Int PicSizeInSamplesY = m_iSourceWidth * m_iSourceHeight; + if(tileFlag) + { + Int maxTileWidth = 0; + Int maxTileHeight = 0; + Int widthInCU = (m_iSourceWidth % m_uiMaxCUWidth) ? m_iSourceWidth/m_uiMaxCUWidth + 1: m_iSourceWidth/m_uiMaxCUWidth; + Int heightInCU = (m_iSourceHeight % m_uiMaxCUHeight) ? m_iSourceHeight/m_uiMaxCUHeight + 1: m_iSourceHeight/m_uiMaxCUHeight; + if(m_tileUniformSpacingFlag) + { + maxTileWidth = m_uiMaxCUWidth*((widthInCU+m_numTileColumnsMinus1)/(m_numTileColumnsMinus1+1)); + maxTileHeight = m_uiMaxCUHeight*((heightInCU+m_numTileRowsMinus1)/(m_numTileRowsMinus1+1)); + // if only the last tile-row is one treeblock higher than the others + // the maxTileHeight becomes smaller if the last row of treeblocks has lower height than the others + if(!((heightInCU-1)%(m_numTileRowsMinus1+1))) + { + maxTileHeight = maxTileHeight - m_uiMaxCUHeight + (m_iSourceHeight % m_uiMaxCUHeight); + } + // if only the last tile-column is one treeblock wider than the others + // the maxTileWidth becomes smaller if the last column of treeblocks has lower width than the others + if(!((widthInCU-1)%(m_numTileColumnsMinus1+1))) + { + maxTileWidth = maxTileWidth - m_uiMaxCUWidth + (m_iSourceWidth % m_uiMaxCUWidth); + } + } + else // not uniform spacing + { + if(m_numTileColumnsMinus1<1) + { + maxTileWidth = m_iSourceWidth; + } + else + { + Int accColumnWidth = 0; + for(Int col=0; col<(m_numTileColumnsMinus1); col++) + { + maxTileWidth = m_tileColumnWidth[col]>maxTileWidth ? m_tileColumnWidth[col]:maxTileWidth; + accColumnWidth += m_tileColumnWidth[col]; + } + maxTileWidth = (widthInCU-accColumnWidth)>maxTileWidth ? m_uiMaxCUWidth*(widthInCU-accColumnWidth):m_uiMaxCUWidth*maxTileWidth; + } + if(m_numTileRowsMinus1<1) + { + maxTileHeight = m_iSourceHeight; + } + else + { + Int accRowHeight = 0; + for(Int row=0; row<(m_numTileRowsMinus1); row++) + { + maxTileHeight = m_tileRowHeight[row]>maxTileHeight ? m_tileRowHeight[row]:maxTileHeight; + accRowHeight += m_tileRowHeight[row]; + } + maxTileHeight = (heightInCU-accRowHeight)>maxTileHeight ? m_uiMaxCUHeight*(heightInCU-accRowHeight):m_uiMaxCUHeight*maxTileHeight; + } + } + Int maxSizeInSamplesY = maxTileWidth*maxTileHeight; + m_minSpatialSegmentationIdc = 4*PicSizeInSamplesY/maxSizeInSamplesY-4; + } + else if(m_iWaveFrontSynchro) + { + m_minSpatialSegmentationIdc = 4*PicSizeInSamplesY/((2*m_iSourceHeight+m_iSourceWidth)*m_uiMaxCUHeight)-4; + } + else if(m_sliceMode == FIXED_NUMBER_OF_CTU) + { + m_minSpatialSegmentationIdc = 4*PicSizeInSamplesY/(m_sliceArgument*m_uiMaxCUWidth*m_uiMaxCUHeight)-4; + } + else + { + m_minSpatialSegmentationIdc = 0; + } + } + + xConfirmPara( m_iWaveFrontSynchro < 0, "WaveFrontSynchro cannot be negative" ); + xConfirmPara( m_iWaveFrontSubstreams <= 0, "WaveFrontSubstreams must be positive" ); + xConfirmPara( m_iWaveFrontSubstreams > 1 && !m_iWaveFrontSynchro, "Must have WaveFrontSynchro > 0 in order to have WaveFrontSubstreams > 1" ); + + xConfirmPara( m_decodedPictureHashSEIEnabled<0 || m_decodedPictureHashSEIEnabled>3, "this hash type is not correct!\n"); + + if (m_toneMappingInfoSEIEnabled) + { + xConfirmPara( m_toneMapCodedDataBitDepth < 8 || m_toneMapCodedDataBitDepth > 14 , "SEIToneMapCodedDataBitDepth must be in rage 8 to 14"); + xConfirmPara( m_toneMapTargetBitDepth < 1 || (m_toneMapTargetBitDepth > 16 && m_toneMapTargetBitDepth < 255) , "SEIToneMapTargetBitDepth must be in rage 1 to 16 or equal to 255"); + xConfirmPara( m_toneMapModelId < 0 || m_toneMapModelId > 4 , "SEIToneMapModelId must be in rage 0 to 4"); + xConfirmPara( m_cameraIsoSpeedValue == 0, "SEIToneMapCameraIsoSpeedValue shall not be equal to 0"); + xConfirmPara( m_exposureIndexValue == 0, "SEIToneMapExposureIndexValue shall not be equal to 0"); + xConfirmPara( m_extendedRangeWhiteLevel < 100, "SEIToneMapExtendedRangeWhiteLevel should be greater than or equal to 100"); + xConfirmPara( m_nominalBlackLevelLumaCodeValue >= m_nominalWhiteLevelLumaCodeValue, "SEIToneMapNominalWhiteLevelLumaCodeValue shall be greater than SEIToneMapNominalBlackLevelLumaCodeValue"); + xConfirmPara( m_extendedWhiteLevelLumaCodeValue < m_nominalWhiteLevelLumaCodeValue, "SEIToneMapExtendedWhiteLevelLumaCodeValue shall be greater than or equal to SEIToneMapNominalWhiteLevelLumaCodeValue"); + } + + if (m_kneeSEIEnabled && !m_kneeSEICancelFlag) + { + xConfirmPara( m_kneeSEINumKneePointsMinus1 < 0 || m_kneeSEINumKneePointsMinus1 > 998, "SEIKneeFunctionNumKneePointsMinus1 must be in the range of 0 to 998"); + for ( UInt i=0; i<=m_kneeSEINumKneePointsMinus1; i++ ){ + xConfirmPara( m_kneeSEIInputKneePoint[i] < 1 || m_kneeSEIInputKneePoint[i] > 999, "SEIKneeFunctionInputKneePointValue must be in the range of 1 to 999"); + xConfirmPara( m_kneeSEIOutputKneePoint[i] < 0 || m_kneeSEIOutputKneePoint[i] > 1000, "SEIKneeFunctionInputKneePointValue must be in the range of 0 to 1000"); + if ( i > 0 ) + { + xConfirmPara( m_kneeSEIInputKneePoint[i-1] >= m_kneeSEIInputKneePoint[i], "The i-th SEIKneeFunctionInputKneePointValue must be greater than the (i-1)-th value"); + xConfirmPara( m_kneeSEIOutputKneePoint[i-1] > m_kneeSEIOutputKneePoint[i], "The i-th SEIKneeFunctionOutputKneePointValue must be greater than or equal to the (i-1)-th value"); + } + } + } + + if ( m_RCEnableRateControl ) + { + if ( m_RCForceIntraQP ) + { + if ( m_RCInitialQP == 0 ) + { + printf( "\nInitial QP for rate control is not specified. Reset not to use force intra QP!" ); + m_RCForceIntraQP = false; + } + } + xConfirmPara( m_uiDeltaQpRD > 0, "Rate control cannot be used together with slice level multiple-QP optimization!\n" ); + } + + xConfirmPara(!m_TransquantBypassEnableFlag && m_CUTransquantBypassFlagForce, "CUTransquantBypassFlagForce cannot be 1 when TransquantBypassEnableFlag is 0"); + + xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2"); + + if (m_framePackingSEIEnabled) + { + xConfirmPara(m_framePackingSEIType < 3 || m_framePackingSEIType > 5 , "SEIFramePackingType must be in rage 3 to 5"); + } + + if (m_segmentedRectFramePackingSEIEnabled) + { + xConfirmPara(m_framePackingSEIEnabled > 0 , "SEISegmentedRectFramePacking must be 0 when SEIFramePacking is 1"); + } + + if((m_numTileColumnsMinus1 <= 0) && (m_numTileRowsMinus1 <= 0) && m_tmctsSEIEnabled) + { + printf("SEITempMotionConstrainedTileSets is set to false to disable 'temporal_motion_constrained_tile_sets' SEI because there are no tiles enabled\n"); + m_tmctsSEIEnabled = false; + } + + if(m_timeCodeSEIEnabled) + { + xConfirmPara(m_timeCodeSEINumTs > MAX_TIMECODE_SEI_SETS, "Number of time sets cannot exceed 3"); + } + +#undef xConfirmPara + if (check_failed) + { + exit(EXIT_FAILURE); + } +} + +/** \todo use of global variables should be removed later + */ +Void TAppEncCfg::xSetGlobal() +{ + // set max CU width & height + g_uiMaxCUWidth = m_uiMaxCUWidth; + g_uiMaxCUHeight = m_uiMaxCUHeight; + + // compute actual CU depth with respect to config depth and max transform size + g_uiAddCUDepth = 0; + while( (m_uiMaxCUWidth>>m_uiMaxCUDepth) > ( 1 << ( m_uiQuadtreeTULog2MinSize + g_uiAddCUDepth ) ) ) g_uiAddCUDepth++; + + g_uiAddCUDepth+=getMaxCUDepthOffset(m_chromaFormatIDC, m_uiQuadtreeTULog2MinSize); // if minimum TU larger than 4x4, allow for additional part indices for 4:2:2 SubTUs. + + m_uiMaxCUDepth += g_uiAddCUDepth; + g_uiAddCUDepth++; + g_uiMaxCUDepth = m_uiMaxCUDepth; + + // set internal bit-depth and constants + for (UInt channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { +#if O0043_BEST_EFFORT_DECODING + g_bitDepthInStream[channelType] = g_bitDepth[channelType] = m_internalBitDepth[channelType]; +#else + g_bitDepth [channelType] = m_internalBitDepth[channelType]; +#endif + g_PCMBitDepth[channelType] = m_bPCMInputBitDepthFlag ? m_MSBExtendedBitDepth[channelType] : m_internalBitDepth[channelType]; + + if (m_useExtendedPrecision) g_maxTrDynamicRange[channelType] = std::max(15, (g_bitDepth[channelType] + 6)); + else g_maxTrDynamicRange[channelType] = 15; + } +} + +const Char *profileToString(const Profile::Name profile) +{ + static const UInt numberOfProfiles = sizeof(strToProfile)/sizeof(*strToProfile); + + for (UInt profileIndex = 0; profileIndex < numberOfProfiles; profileIndex++) + { + if (strToProfile[profileIndex].value == profile) return strToProfile[profileIndex].str; + } + + //if we get here, we didn't find this profile in the list - so there is an error + std::cerr << "ERROR: Unknown profile \"" << profile << "\" in profileToString" << std::endl; + assert(false); + exit(1); + return ""; +} + +Void TAppEncCfg::xPrintParameter() +{ + printf("\n"); + printf("Input File : %s\n", m_pchInputFile ); + printf("Bitstream File : %s\n", m_pchBitstreamFile ); + printf("Reconstruction File : %s\n", m_pchReconFile ); + printf("Real Format : %dx%d %dHz\n", m_iSourceWidth - m_confWinLeft - m_confWinRight, m_iSourceHeight - m_confWinTop - m_confWinBottom, m_iFrameRate ); + printf("Internal Format : %dx%d %dHz\n", m_iSourceWidth, m_iSourceHeight, m_iFrameRate ); + printf("Sequence PSNR output : %s\n", (m_printMSEBasedSequencePSNR ? "Linear average, MSE-based" : "Linear average only") ); + printf("Sequence MSE output : %s\n", (m_printSequenceMSE ? "Enabled" : "Disabled") ); + printf("Frame MSE output : %s\n", (m_printFrameMSE ? "Enabled" : "Disabled") ); + printf("Cabac-zero-word-padding : %s\n", (m_cabacZeroWordPaddingEnabled? "Enabled" : "Disabled") ); + if (m_isField) + { + printf("Frame/Field : Field based coding\n"); + printf("Field index : %u - %d (%d fields)\n", m_FrameSkip, m_FrameSkip+m_framesToBeEncoded-1, m_framesToBeEncoded ); + printf("Field Order : %s field first\n", m_isTopFieldFirst?"Top":"Bottom"); + + } + else + { + printf("Frame/Field : Frame based coding\n"); + printf("Frame index : %u - %d (%d frames)\n", m_FrameSkip, m_FrameSkip+m_framesToBeEncoded-1, m_framesToBeEncoded ); + } + if (m_profile == Profile::MAINREXT) + { + const UInt intraIdx = m_intraConstraintFlag ? 1:0; + const UInt bitDepthIdx = (m_bitDepthConstraint == 8 ? 0 : (m_bitDepthConstraint ==10 ? 1 : (m_bitDepthConstraint == 12 ? 2 : (m_bitDepthConstraint == 16 ? 3 : 4 )))); + const UInt chromaFormatIdx = UInt(m_chromaFormatConstraint); + const ExtendedProfileName validProfileName = (bitDepthIdx > 3 || chromaFormatIdx>3) ? NONE : validRExtProfileNames[intraIdx][bitDepthIdx][chromaFormatIdx]; + std::string rextSubProfile; + if (validProfileName!=NONE) rextSubProfile=enumToString(strToExtendedProfile, sizeof(strToExtendedProfile)/sizeof(*strToExtendedProfile), validProfileName); + if (rextSubProfile == "main_444_16") rextSubProfile="main_444_16 [NON STANDARD]"; + printf("Profile : %s (%s)\n", profileToString(m_profile), (rextSubProfile.empty())?"INVALID REXT PROFILE":rextSubProfile.c_str() ); + } + else + { + printf("Profile : %s\n", profileToString(m_profile) ); + } + printf("CU size / depth : %d / %d\n", m_uiMaxCUWidth, m_uiMaxCUDepth ); + printf("RQT trans. size (min / max) : %d / %d\n", 1 << m_uiQuadtreeTULog2MinSize, 1 << m_uiQuadtreeTULog2MaxSize ); + printf("Max RQT depth inter : %d\n", m_uiQuadtreeTUMaxDepthInter); + printf("Max RQT depth intra : %d\n", m_uiQuadtreeTUMaxDepthIntra); + printf("Min PCM size : %d\n", 1 << m_uiPCMLog2MinSize); + printf("Motion search range : %d\n", m_iSearchRange ); + printf("Intra period : %d\n", m_iIntraPeriod ); + printf("Decoding refresh type : %d\n", m_iDecodingRefreshType ); + printf("QP : %5.2f\n", m_fQP ); + printf("Max dQP signaling depth : %d\n", m_iMaxCuDQPDepth); + + printf("Cb QP Offset : %d\n", m_cbQpOffset ); + printf("Cr QP Offset : %d\n", m_crQpOffset); + printf("Max CU chroma QP adjustment depth : %d\n", m_maxCUChromaQpAdjustmentDepth); + printf("QP adaptation : %d (range=%d)\n", m_bUseAdaptiveQP, (m_bUseAdaptiveQP ? m_iQPAdaptationRange : 0) ); + printf("GOP size : %d\n", m_iGOPSize ); + printf("Input bit depth : (Y:%d, C:%d)\n", m_inputBitDepth[CHANNEL_TYPE_LUMA], m_inputBitDepth[CHANNEL_TYPE_CHROMA] ); + printf("MSB-extended bit depth : (Y:%d, C:%d)\n", m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA], m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] ); + printf("Internal bit depth : (Y:%d, C:%d)\n", m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA] ); + printf("PCM sample bit depth : (Y:%d, C:%d)\n", g_PCMBitDepth[CHANNEL_TYPE_LUMA], g_PCMBitDepth[CHANNEL_TYPE_CHROMA] ); + printf("Extended precision processing : %s\n", (m_useExtendedPrecision ? "Enabled" : "Disabled") ); + printf("Intra reference smoothing : %s\n", (m_enableIntraReferenceSmoothing ? "Enabled" : "Disabled") ); + printf("Implicit residual DPCM : %s\n", (m_useResidualDPCM[RDPCM_SIGNAL_IMPLICIT] ? "Enabled" : "Disabled") ); + printf("Explicit residual DPCM : %s\n", (m_useResidualDPCM[RDPCM_SIGNAL_EXPLICIT] ? "Enabled" : "Disabled") ); + printf("Residual rotation : %s\n", (m_useResidualRotation ? "Enabled" : "Disabled") ); + printf("Single significance map context : %s\n", (m_useSingleSignificanceMapContext ? "Enabled" : "Disabled") ); + printf("Cross-component prediction : %s\n", (m_useCrossComponentPrediction ? (m_reconBasedCrossCPredictionEstimate ? "Enabled (reconstructed-residual-based estimate)" : "Enabled (encoder-side-residual-based estimate)") : "Disabled") ); + printf("High-precision prediction weight : %s\n", (m_useHighPrecisionPredictionWeighting ? "Enabled" : "Disabled") ); + printf("Golomb-Rice parameter adaptation : %s\n", (m_useGolombRiceParameterAdaptation ? "Enabled" : "Disabled") ); + printf("CABAC bypass bit alignment : %s\n", (m_alignCABACBeforeBypass ? "Enabled" : "Disabled") ); + if (m_bUseSAO) + { + printf("Sao Luma Offset bit shifts : %d\n", m_saoOffsetBitShift[CHANNEL_TYPE_LUMA]); + printf("Sao Chroma Offset bit shifts : %d\n", m_saoOffsetBitShift[CHANNEL_TYPE_CHROMA]); + } + + switch (m_costMode) + { + case COST_STANDARD_LOSSY: printf("Cost function: : Lossy coding (default)\n"); break; + case COST_SEQUENCE_LEVEL_LOSSLESS: printf("Cost function: : Sequence_level_lossless coding\n"); break; + case COST_LOSSLESS_CODING: printf("Cost function: : Lossless coding with fixed QP of %d\n", LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP); break; + case COST_MIXED_LOSSLESS_LOSSY_CODING: printf("Cost function: : Mixed_lossless_lossy coding with QP'=%d for lossless evaluation\n", LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME); break; + default: printf("Cost function: : Unknown\n"); break; + } + + printf("RateControl : %d\n", m_RCEnableRateControl ); + + if(m_RCEnableRateControl) + { + printf("TargetBitrate : %d\n", m_RCTargetBitrate ); + printf("KeepHierarchicalBit : %d\n", m_RCKeepHierarchicalBit ); + printf("LCULevelRC : %d\n", m_RCLCULevelRC ); + printf("UseLCUSeparateModel : %d\n", m_RCUseLCUSeparateModel ); + printf("InitialQP : %d\n", m_RCInitialQP ); + printf("ForceIntraQP : %d\n", m_RCForceIntraQP ); + } + + printf("Max Num Merge Candidates : %d\n", m_maxNumMergeCand); + printf("\n"); + + printf("TOOL CFG: "); + printf("IBD:%d ", ((g_bitDepth[CHANNEL_TYPE_LUMA] > m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA]) || (g_bitDepth[CHANNEL_TYPE_CHROMA] > m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA]))); + printf("HAD:%d ", m_bUseHADME ); + printf("RDQ:%d ", m_useRDOQ ); + printf("RDQTS:%d ", m_useRDOQTS ); + printf("RDpenalty:%d ", m_rdPenalty ); + printf("SQP:%d ", m_uiDeltaQpRD ); + printf("ASR:%d ", m_bUseASR ); + printf("FEN:%d ", m_bUseFastEnc ); + printf("ECU:%d ", m_bUseEarlyCU ); + printf("FDM:%d ", m_useFastDecisionForMerge ); + printf("CFM:%d ", m_bUseCbfFastMode ); + printf("ESD:%d ", m_useEarlySkipDetection ); + printf("RQT:%d ", 1 ); + printf("TransformSkip:%d ", m_useTransformSkip ); + printf("TransformSkipFast:%d ", m_useTransformSkipFast ); + printf("TransformSkipLog2MaxSize:%d ", m_transformSkipLog2MaxSize); + printf("Slice: M=%d ", m_sliceMode); + if (m_sliceMode!=NO_SLICES) + { + printf("A=%d ", m_sliceArgument); + } + printf("SliceSegment: M=%d ",m_sliceSegmentMode); + if (m_sliceSegmentMode!=NO_SLICES) + { + printf("A=%d ", m_sliceSegmentArgument); + } + printf("CIP:%d ", m_bUseConstrainedIntraPred); + printf("SAO:%d ", (m_bUseSAO)?(1):(0)); + printf("PCM:%d ", (m_usePCM && (1< +#include +//! \ingroup TAppEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// encoder configuration class +class TAppEncCfg +{ +protected: + // file I/O + Char* m_pchInputFile; ///< source file name + Char* m_pchBitstreamFile; ///< output bitstream file + Char* m_pchReconFile; ///< output reconstruction file + Double m_adLambdaModifier[ MAX_TLAYER ]; ///< Lambda modifier array for each temporal layer + // source specification + Int m_iFrameRate; ///< source frame-rates (Hz) + UInt m_FrameSkip; ///< number of skipped frames from the beginning + Int m_iSourceWidth; ///< source width in pixel + Int m_iSourceHeight; ///< source height in pixel (when interlaced = field height) + + Int m_iSourceHeightOrg; ///< original source height in pixel (when interlaced = frame height) + + Bool m_isField; ///< enable field coding + Bool m_isTopFieldFirst; + + Int m_conformanceWindowMode; + Int m_confWinLeft; + Int m_confWinRight; + Int m_confWinTop; + Int m_confWinBottom; + Int m_framesToBeEncoded; ///< number of encoded frames + Int m_aiPad[2]; ///< number of padded pixels for width and height + InputColourSpaceConversion m_inputColourSpaceConvert; ///< colour space conversion to apply to input video + Bool m_snrInternalColourSpace; ///< if true, then no colour space conversion is applied for snr calculation, otherwise inverse of input is applied. + Bool m_outputInternalColourSpace; ///< if true, then no colour space conversion is applied for reconstructed video, otherwise inverse of input is applied. + ChromaFormat m_InputChromaFormatIDC; + + Bool m_printMSEBasedSequencePSNR; + Bool m_printFrameMSE; + Bool m_printSequenceMSE; + Bool m_cabacZeroWordPaddingEnabled; + + // profile/level + Profile::Name m_profile; + Level::Tier m_levelTier; + Level::Name m_level; + UInt m_bitDepthConstraint; + ChromaFormat m_chromaFormatConstraint; + Bool m_intraConstraintFlag; + Bool m_lowerBitRateConstraintFlag; + Bool m_progressiveSourceFlag; + Bool m_interlacedSourceFlag; + Bool m_nonPackedConstraintFlag; + Bool m_frameOnlyConstraintFlag; + + // coding structure + Int m_iIntraPeriod; ///< period of I-slice (random access period) + Int m_iDecodingRefreshType; ///< random access type + Int m_iGOPSize; ///< GOP size of hierarchical structure + Int m_extraRPSs; ///< extra RPSs added to handle CRA + GOPEntry m_GOPList[MAX_GOP]; ///< the coding structure entries from the config file + Int m_numReorderPics[MAX_TLAYER]; ///< total number of reorder pictures + Int m_maxDecPicBuffering[MAX_TLAYER]; ///< total number of pictures in the decoded picture buffer + Bool m_useCrossComponentPrediction; ///< flag enabling the use of cross-component prediction + Bool m_reconBasedCrossCPredictionEstimate; ///< causes the alpha calculation in encoder search to be based on the decoded residual rather than the pre-transform encoder-side residual + UInt m_saoOffsetBitShift[MAX_NUM_CHANNEL_TYPE]; ///< number of bits for the upward bit shift operation on the decoded SAO offsets + Bool m_useTransformSkip; ///< flag for enabling intra transform skipping + Bool m_useTransformSkipFast; ///< flag for enabling fast intra transform skipping + UInt m_transformSkipLog2MaxSize; ///< transform-skip maximum size (minimum of 2) + Bool m_useResidualRotation; ///< control flag for transform-skip/transquant-bypass residual rotation + Bool m_useSingleSignificanceMapContext; ///< control flag for transform-skip/transquant-bypass single significance map context + Bool m_useResidualDPCM[NUMBER_OF_RDPCM_SIGNALLING_MODES];///< control flags for residual DPCM + Bool m_enableAMP; + Bool m_useGolombRiceParameterAdaptation; ///< control flag for Golomb-Rice parameter adaptation over each slice + Bool m_alignCABACBeforeBypass; + + // coding quality + Double m_fQP; ///< QP value of key-picture (floating point) + Int m_iQP; ///< QP value of key-picture (integer) + Char* m_pchdQPFile; ///< QP offset for each slice (initialized from external file) + Int* m_aidQP; ///< array of slice QP values + Int m_iMaxDeltaQP; ///< max. |delta QP| + UInt m_uiDeltaQpRD; ///< dQP range for multi-pass slice QP optimization + Int m_iMaxCuDQPDepth; ///< Max. depth for a minimum CuDQPSize (0:default) + Int m_maxCUChromaQpAdjustmentDepth; + + Int m_cbQpOffset; ///< Chroma Cb QP Offset (0:default) + Int m_crQpOffset; ///< Chroma Cr QP Offset (0:default) + +#if ADAPTIVE_QP_SELECTION + Bool m_bUseAdaptQpSelect; +#endif + TComSEIMasteringDisplay m_masteringDisplay; + + Bool m_bUseAdaptiveQP; ///< Flag for enabling QP adaptation based on a psycho-visual model + Int m_iQPAdaptationRange; ///< dQP range by QP adaptation + + Int m_maxTempLayer; ///< Max temporal layer + + // coding unit (CU) definition + // TODO: Remove MaxCUWidth/MaxCUHeight and replace with MaxCUSize. + UInt m_uiMaxCUWidth; ///< max. CU width in pixel + UInt m_uiMaxCUHeight; ///< max. CU height in pixel + UInt m_uiMaxCUDepth; ///< max. CU depth + + // transfom unit (TU) definition + UInt m_uiQuadtreeTULog2MaxSize; + UInt m_uiQuadtreeTULog2MinSize; + + UInt m_uiQuadtreeTUMaxDepthInter; + UInt m_uiQuadtreeTUMaxDepthIntra; + + // coding tools (bit-depth) + Int m_inputBitDepth [MAX_NUM_CHANNEL_TYPE]; ///< bit-depth of input file + Int m_outputBitDepth [MAX_NUM_CHANNEL_TYPE]; ///< bit-depth of output file + Int m_MSBExtendedBitDepth[MAX_NUM_CHANNEL_TYPE]; ///< bit-depth of input samples after MSB extension + Int m_internalBitDepth[MAX_NUM_CHANNEL_TYPE]; ///< bit-depth codec operates at (input/output files will be converted) + Bool m_useExtendedPrecision; + Bool m_useHighPrecisionPredictionWeighting; + + //coding tools (chroma format) + ChromaFormat m_chromaFormatIDC; + + // coding tools (PCM bit-depth) + Bool m_bPCMInputBitDepthFlag; ///< 0: PCM bit-depth is internal bit-depth. 1: PCM bit-depth is input bit-depth. + + // coding tool (SAO) + Bool m_bUseSAO; + Int m_maxNumOffsetsPerPic; ///< SAO maximun number of offset per picture + Bool m_saoCtuBoundary; ///< SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas + // coding tools (loop filter) + Bool m_bLoopFilterDisable; ///< flag for using deblocking filter + Bool m_loopFilterOffsetInPPS; ///< offset for deblocking filter in 0 = slice header, 1 = PPS + Int m_loopFilterBetaOffsetDiv2; ///< beta offset for deblocking filter + Int m_loopFilterTcOffsetDiv2; ///< tc offset for deblocking filter + Bool m_DeblockingFilterControlPresent; ///< deblocking filter control present flag in PPS + Bool m_DeblockingFilterMetric; ///< blockiness metric in encoder + + // coding tools (PCM) + Bool m_usePCM; ///< flag for using IPCM + UInt m_pcmLog2MaxSize; ///< log2 of maximum PCM block size + UInt m_uiPCMLog2MinSize; ///< log2 of minimum PCM block size + Bool m_bPCMFilterDisableFlag; ///< PCM filter disable flag + Bool m_enableIntraReferenceSmoothing; ///< flag for enabling(default)/disabling intra reference smoothing/filtering + + // coding tools (encoder-only parameters) + Bool m_bUseASR; ///< flag for using adaptive motion search range + Bool m_bUseHADME; ///< flag for using HAD in sub-pel ME + Bool m_useRDOQ; ///< flag for using RD optimized quantization + Bool m_useRDOQTS; ///< flag for using RD optimized quantization for transform skip + Int m_rdPenalty; ///< RD-penalty for 32x32 TU for intra in non-intra slices (0: no RD-penalty, 1: RD-penalty, 2: maximum RD-penalty) + Int m_iFastSearch; ///< ME mode, 0 = full, 1 = diamond, 2 = PMVFAST + Int m_iSearchRange; ///< ME search range + Int m_bipredSearchRange; ///< ME search range for bipred refinement + Bool m_bUseFastEnc; ///< flag for using fast encoder setting + Bool m_bUseEarlyCU; ///< flag for using Early CU setting + Bool m_useFastDecisionForMerge; ///< flag for using Fast Decision Merge RD-Cost + Bool m_bUseCbfFastMode; ///< flag for using Cbf Fast PU Mode Decision + Bool m_useEarlySkipDetection; ///< flag for using Early SKIP Detection + Int m_sliceMode; ///< 0: no slice limits, 1 : max number of CTBs per slice, 2: max number of bytes per slice, + ///< 3: max number of tiles per slice + Int m_sliceArgument; ///< argument according to selected slice mode + Int m_sliceSegmentMode; ///< 0: no slice segment limits, 1 : max number of CTBs per slice segment, 2: max number of bytes per slice segment, + ///< 3: max number of tiles per slice segment + Int m_sliceSegmentArgument; ///< argument according to selected slice segment mode + + Bool m_bLFCrossSliceBoundaryFlag; ///< 1: filter across slice boundaries 0: do not filter across slice boundaries + Bool m_bLFCrossTileBoundaryFlag; ///< 1: filter across tile boundaries 0: do not filter across tile boundaries + Bool m_tileUniformSpacingFlag; + Int m_numTileColumnsMinus1; + Int m_numTileRowsMinus1; + std::vector m_tileColumnWidth; + std::vector m_tileRowHeight; + Int m_iWaveFrontSynchro; //< 0: no WPP. >= 1: WPP is enabled, the "Top right" from which inheritance occurs is this LCU offset in the line above the current. + Int m_iWaveFrontFlush; //< enable(1)/disable(0) the CABAC flush at the end of each line of LCUs. + Int m_iWaveFrontSubstreams; //< If iWaveFrontSynchro, this is the number of substreams per frame (dependent tiles) or per tile (independent tiles). + + Bool m_bUseConstrainedIntraPred; ///< flag for using constrained intra prediction + + Int m_decodedPictureHashSEIEnabled; ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message + Int m_recoveryPointSEIEnabled; + Int m_bufferingPeriodSEIEnabled; + Int m_pictureTimingSEIEnabled; + Bool m_toneMappingInfoSEIEnabled; + Bool m_chromaSamplingFilterSEIenabled; + Int m_chromaSamplingHorFilterIdc; + Int m_chromaSamplingVerFilterIdc; + Int m_toneMapId; + Bool m_toneMapCancelFlag; + Bool m_toneMapPersistenceFlag; + Int m_toneMapCodedDataBitDepth; + Int m_toneMapTargetBitDepth; + Int m_toneMapModelId; + Int m_toneMapMinValue; + Int m_toneMapMaxValue; + Int m_sigmoidMidpoint; + Int m_sigmoidWidth; + Int m_numPivots; + Int m_cameraIsoSpeedIdc; + Int m_cameraIsoSpeedValue; + Int m_exposureIndexIdc; + Int m_exposureIndexValue; + Int m_exposureCompensationValueSignFlag; + Int m_exposureCompensationValueNumerator; + Int m_exposureCompensationValueDenomIdc; + Int m_refScreenLuminanceWhite; + Int m_extendedRangeWhiteLevel; + Int m_nominalBlackLevelLumaCodeValue; + Int m_nominalWhiteLevelLumaCodeValue; + Int m_extendedWhiteLevelLumaCodeValue; + Int* m_startOfCodedInterval; + Int* m_codedPivotValue; + Int* m_targetPivotValue; + Int m_framePackingSEIEnabled; + Int m_framePackingSEIType; + Int m_framePackingSEIId; + Int m_framePackingSEIQuincunx; + Int m_framePackingSEIInterpretation; + Int m_segmentedRectFramePackingSEIEnabled; + Bool m_segmentedRectFramePackingSEICancel; + Int m_segmentedRectFramePackingSEIType; + Bool m_segmentedRectFramePackingSEIPersistence; + Int m_displayOrientationSEIAngle; + Int m_temporalLevel0IndexSEIEnabled; + Int m_gradualDecodingRefreshInfoEnabled; + Int m_noDisplaySEITLayer; + Int m_decodingUnitInfoSEIEnabled; + Int m_SOPDescriptionSEIEnabled; + Int m_scalableNestingSEIEnabled; + Bool m_tmctsSEIEnabled; + Bool m_timeCodeSEIEnabled; + Int m_timeCodeSEINumTs; + TComSEITimeSet m_timeSetArray[MAX_TIMECODE_SEI_SETS]; + Bool m_kneeSEIEnabled; + Int m_kneeSEIId; + Bool m_kneeSEICancelFlag; + Bool m_kneeSEIPersistenceFlag; + Int m_kneeSEIInputDrange; + Int m_kneeSEIInputDispLuminance; + Int m_kneeSEIOutputDrange; + Int m_kneeSEIOutputDispLuminance; + Int m_kneeSEINumKneePointsMinus1; + Int* m_kneeSEIInputKneePoint; + Int* m_kneeSEIOutputKneePoint; + // weighted prediction + Bool m_useWeightedPred; ///< Use of weighted prediction in P slices + Bool m_useWeightedBiPred; ///< Use of bi-directional weighted prediction in B slices + + UInt m_log2ParallelMergeLevel; ///< Parallel merge estimation region + UInt m_maxNumMergeCand; ///< Max number of merge candidates + + Int m_TMVPModeId; + Int m_signHideFlag; + Bool m_RCEnableRateControl; ///< enable rate control or not + Int m_RCTargetBitrate; ///< target bitrate when rate control is enabled + Int m_RCKeepHierarchicalBit; ///< 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation + Bool m_RCLCULevelRC; ///< true: LCU level rate control; false: picture level rate control NOTE: code-tidy - rename to m_RCCtuLevelRC + Bool m_RCUseLCUSeparateModel; ///< use separate R-lambda model at LCU level NOTE: code-tidy - rename to m_RCUseCtuSeparateModel + Int m_RCInitialQP; ///< inital QP for rate control + Bool m_RCForceIntraQP; ///< force all intra picture to use initial QP or not + ScalingListMode m_useScalingListId; ///< using quantization matrix + Char* m_scalingListFile; ///< quantization matrix file name + + Bool m_TransquantBypassEnableFlag; ///< transquant_bypass_enable_flag setting in PPS. + Bool m_CUTransquantBypassFlagForce; ///< if transquant_bypass_enable_flag, then, if true, all CU transquant bypass flags will be set to true. + CostMode m_costMode; ///< Cost mode to use + + Bool m_recalculateQPAccordingToLambda; ///< recalculate QP value according to the lambda value + Bool m_useStrongIntraSmoothing; ///< enable strong intra smoothing for 32x32 blocks where the reference samples are flat + Int m_activeParameterSetsSEIEnabled; + + Bool m_vuiParametersPresentFlag; ///< enable generation of VUI parameters + Bool m_aspectRatioInfoPresentFlag; ///< Signals whether aspect_ratio_idc is present + Int m_aspectRatioIdc; ///< aspect_ratio_idc + Int m_sarWidth; ///< horizontal size of the sample aspect ratio + Int m_sarHeight; ///< vertical size of the sample aspect ratio + Bool m_overscanInfoPresentFlag; ///< Signals whether overscan_appropriate_flag is present + Bool m_overscanAppropriateFlag; ///< Indicates whether conformant decoded pictures are suitable for display using overscan + Bool m_videoSignalTypePresentFlag; ///< Signals whether video_format, video_full_range_flag, and colour_description_present_flag are present + Int m_videoFormat; ///< Indicates representation of pictures + Bool m_videoFullRangeFlag; ///< Indicates the black level and range of luma and chroma signals + Bool m_colourDescriptionPresentFlag; ///< Signals whether colour_primaries, transfer_characteristics and matrix_coefficients are present + Int m_colourPrimaries; ///< Indicates chromaticity coordinates of the source primaries + Int m_transferCharacteristics; ///< Indicates the opto-electronic transfer characteristics of the source + Int m_matrixCoefficients; ///< Describes the matrix coefficients used in deriving luma and chroma from RGB primaries + Bool m_chromaLocInfoPresentFlag; ///< Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present + Int m_chromaSampleLocTypeTopField; ///< Specifies the location of chroma samples for top field + Int m_chromaSampleLocTypeBottomField; ///< Specifies the location of chroma samples for bottom field + Bool m_neutralChromaIndicationFlag; ///< Indicates that the value of all decoded chroma samples is equal to 1<<(BitDepthCr-1) + Bool m_defaultDisplayWindowFlag; ///< Indicates the presence of the default window parameters + Int m_defDispWinLeftOffset; ///< Specifies the left offset from the conformance window of the default window + Int m_defDispWinRightOffset; ///< Specifies the right offset from the conformance window of the default window + Int m_defDispWinTopOffset; ///< Specifies the top offset from the conformance window of the default window + Int m_defDispWinBottomOffset; ///< Specifies the bottom offset from the conformance window of the default window + Bool m_frameFieldInfoPresentFlag; ///< Indicates that pic_struct values are present in picture timing SEI messages + Bool m_pocProportionalToTimingFlag; ///< Indicates that the POC value is proportional to the output time w.r.t. first picture in CVS + Int m_numTicksPocDiffOneMinus1; ///< Number of ticks minus 1 that for a POC difference of one + Bool m_bitstreamRestrictionFlag; ///< Signals whether bitstream restriction parameters are present + Bool m_tilesFixedStructureFlag; ///< Indicates that each active picture parameter set has the same values of the syntax elements related to tiles + Bool m_motionVectorsOverPicBoundariesFlag; ///< Indicates that no samples outside the picture boundaries are used for inter prediction + Int m_minSpatialSegmentationIdc; ///< Indicates the maximum size of the spatial segments in the pictures in the coded video sequence + Int m_maxBytesPerPicDenom; ///< Indicates a number of bytes not exceeded by the sum of the sizes of the VCL NAL units associated with any coded picture + Int m_maxBitsPerMinCuDenom; ///< Indicates an upper bound for the number of bits of coding_unit() data + Int m_log2MaxMvLengthHorizontal; ///< Indicate the maximum absolute value of a decoded horizontal MV component in quarter-pel luma units + Int m_log2MaxMvLengthVertical; ///< Indicate the maximum absolute value of a decoded vertical MV component in quarter-pel luma units + + // internal member functions + Void xSetGlobal (); ///< set global variables + Void xCheckParameter (); ///< check validity of configuration values + Void xPrintParameter (); ///< print configuration values + Void xPrintUsage (); ///< print usage +public: + TAppEncCfg(); + virtual ~TAppEncCfg(); + +public: + Void create (); ///< create option handling class + Void destroy (); ///< destroy option handling class + Bool parseCfg ( Int argc, Char* argv[] ); ///< parse configuration file to fill member variables + + Int m_verboseLevel; /* verbose level */ +};// END CLASS DEFINITION TAppEncCfg + +//! \} + +#endif // __TAPPENCCFG__ + diff --git a/jctvc/TAppEncTop.cpp b/jctvc/TAppEncTop.cpp new file mode 100644 index 0000000..fc0798e --- /dev/null +++ b/jctvc/TAppEncTop.cpp @@ -0,0 +1,695 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TAppEncTop.cpp + \brief Encoder application class +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "TAppEncTop.h" +#include "TLibEncoder/AnnexBwrite.h" + +using namespace std; + +//! \ingroup TAppEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / initialization / destroy +// ==================================================================================================================== + +TAppEncTop::TAppEncTop() +{ + m_iFrameRcvd = 0; + m_totalBytes = 0; + m_essentialBytes = 0; +} + +TAppEncTop::~TAppEncTop() +{ +} + +Void TAppEncTop::xInitLibCfg() +{ + TComVPS vps; + + vps.setMaxTLayers ( m_maxTempLayer ); + if (m_maxTempLayer == 1) + { + vps.setTemporalNestingFlag(true); + } + vps.setMaxLayers ( 1 ); + for(Int i = 0; i < MAX_TLAYER; i++) + { + vps.setNumReorderPics ( m_numReorderPics[i], i ); + vps.setMaxDecPicBuffering ( m_maxDecPicBuffering[i], i ); + } + m_cTEncTop.setVPS(&vps); + + m_cTEncTop.setProfile ( m_profile); + m_cTEncTop.setLevel ( m_levelTier, m_level); + m_cTEncTop.setProgressiveSourceFlag ( m_progressiveSourceFlag); + m_cTEncTop.setInterlacedSourceFlag ( m_interlacedSourceFlag); + m_cTEncTop.setNonPackedConstraintFlag ( m_nonPackedConstraintFlag); + m_cTEncTop.setFrameOnlyConstraintFlag ( m_frameOnlyConstraintFlag); + m_cTEncTop.setBitDepthConstraintValue ( m_bitDepthConstraint ); + m_cTEncTop.setChromaFormatConstraintValue ( m_chromaFormatConstraint ); + m_cTEncTop.setIntraConstraintFlag ( m_intraConstraintFlag ); + m_cTEncTop.setLowerBitRateConstraintFlag ( m_lowerBitRateConstraintFlag ); + + m_cTEncTop.setPrintMSEBasedSequencePSNR ( m_printMSEBasedSequencePSNR); + m_cTEncTop.setPrintFrameMSE ( m_printFrameMSE); + m_cTEncTop.setPrintSequenceMSE ( m_printSequenceMSE); + m_cTEncTop.setCabacZeroWordPaddingEnabled ( m_cabacZeroWordPaddingEnabled ); + + m_cTEncTop.setFrameRate ( m_iFrameRate ); + m_cTEncTop.setFrameSkip ( m_FrameSkip ); + m_cTEncTop.setSourceWidth ( m_iSourceWidth ); + m_cTEncTop.setSourceHeight ( m_iSourceHeight ); + m_cTEncTop.setConformanceWindow ( m_confWinLeft, m_confWinRight, m_confWinTop, m_confWinBottom ); + m_cTEncTop.setFramesToBeEncoded ( m_framesToBeEncoded ); + + //====== Coding Structure ======== + m_cTEncTop.setIntraPeriod ( m_iIntraPeriod ); + m_cTEncTop.setDecodingRefreshType ( m_iDecodingRefreshType ); + m_cTEncTop.setGOPSize ( m_iGOPSize ); + m_cTEncTop.setGopList ( m_GOPList ); + m_cTEncTop.setExtraRPSs ( m_extraRPSs ); + for(Int i = 0; i < MAX_TLAYER; i++) + { + m_cTEncTop.setNumReorderPics ( m_numReorderPics[i], i ); + m_cTEncTop.setMaxDecPicBuffering ( m_maxDecPicBuffering[i], i ); + } + for( UInt uiLoop = 0; uiLoop < MAX_TLAYER; ++uiLoop ) + { + m_cTEncTop.setLambdaModifier ( uiLoop, m_adLambdaModifier[ uiLoop ] ); + } + m_cTEncTop.setQP ( m_iQP ); + + m_cTEncTop.setPad ( m_aiPad ); + + m_cTEncTop.setMaxTempLayer ( m_maxTempLayer ); + m_cTEncTop.setUseAMP( m_enableAMP ); + + //===== Slice ======== + + //====== Loop/Deblock Filter ======== + m_cTEncTop.setLoopFilterDisable ( m_bLoopFilterDisable ); + m_cTEncTop.setLoopFilterOffsetInPPS ( m_loopFilterOffsetInPPS ); + m_cTEncTop.setLoopFilterBetaOffset ( m_loopFilterBetaOffsetDiv2 ); + m_cTEncTop.setLoopFilterTcOffset ( m_loopFilterTcOffsetDiv2 ); + m_cTEncTop.setDeblockingFilterControlPresent ( m_DeblockingFilterControlPresent); + m_cTEncTop.setDeblockingFilterMetric ( m_DeblockingFilterMetric ); + + //====== Motion search ======== + m_cTEncTop.setFastSearch ( m_iFastSearch ); + m_cTEncTop.setSearchRange ( m_iSearchRange ); + m_cTEncTop.setBipredSearchRange ( m_bipredSearchRange ); + + //====== Quality control ======== + m_cTEncTop.setMaxDeltaQP ( m_iMaxDeltaQP ); + m_cTEncTop.setMaxCuDQPDepth ( m_iMaxCuDQPDepth ); + m_cTEncTop.setMaxCUChromaQpAdjustmentDepth ( m_maxCUChromaQpAdjustmentDepth ); + m_cTEncTop.setChromaCbQpOffset ( m_cbQpOffset ); + m_cTEncTop.setChromaCrQpOffset ( m_crQpOffset ); + + m_cTEncTop.setChromaFormatIdc ( m_chromaFormatIDC ); + +#if ADAPTIVE_QP_SELECTION + m_cTEncTop.setUseAdaptQpSelect ( m_bUseAdaptQpSelect ); +#endif + + m_cTEncTop.setUseAdaptiveQP ( m_bUseAdaptiveQP ); + m_cTEncTop.setQPAdaptationRange ( m_iQPAdaptationRange ); + m_cTEncTop.setUseExtendedPrecision ( m_useExtendedPrecision ); + m_cTEncTop.setUseHighPrecisionPredictionWeighting ( m_useHighPrecisionPredictionWeighting ); + //====== Tool list ======== + m_cTEncTop.setDeltaQpRD ( m_uiDeltaQpRD ); + m_cTEncTop.setUseASR ( m_bUseASR ); + m_cTEncTop.setUseHADME ( m_bUseHADME ); + m_cTEncTop.setdQPs ( m_aidQP ); + m_cTEncTop.setUseRDOQ ( m_useRDOQ ); + m_cTEncTop.setUseRDOQTS ( m_useRDOQTS ); + m_cTEncTop.setRDpenalty ( m_rdPenalty ); + m_cTEncTop.setQuadtreeTULog2MaxSize ( m_uiQuadtreeTULog2MaxSize ); + m_cTEncTop.setQuadtreeTULog2MinSize ( m_uiQuadtreeTULog2MinSize ); + m_cTEncTop.setQuadtreeTUMaxDepthInter ( m_uiQuadtreeTUMaxDepthInter ); + m_cTEncTop.setQuadtreeTUMaxDepthIntra ( m_uiQuadtreeTUMaxDepthIntra ); + m_cTEncTop.setUseFastEnc ( m_bUseFastEnc ); + m_cTEncTop.setUseEarlyCU ( m_bUseEarlyCU ); + m_cTEncTop.setUseFastDecisionForMerge ( m_useFastDecisionForMerge ); + m_cTEncTop.setUseCbfFastMode ( m_bUseCbfFastMode ); + m_cTEncTop.setUseEarlySkipDetection ( m_useEarlySkipDetection ); + m_cTEncTop.setUseCrossComponentPrediction ( m_useCrossComponentPrediction ); + m_cTEncTop.setUseReconBasedCrossCPredictionEstimate ( m_reconBasedCrossCPredictionEstimate ); + m_cTEncTop.setSaoOffsetBitShift ( CHANNEL_TYPE_LUMA , m_saoOffsetBitShift[CHANNEL_TYPE_LUMA] ); + m_cTEncTop.setSaoOffsetBitShift ( CHANNEL_TYPE_CHROMA, m_saoOffsetBitShift[CHANNEL_TYPE_CHROMA] ); + m_cTEncTop.setUseTransformSkip ( m_useTransformSkip ); + m_cTEncTop.setUseTransformSkipFast ( m_useTransformSkipFast ); + m_cTEncTop.setUseResidualRotation ( m_useResidualRotation ); + m_cTEncTop.setUseSingleSignificanceMapContext ( m_useSingleSignificanceMapContext ); + m_cTEncTop.setUseGolombRiceParameterAdaptation ( m_useGolombRiceParameterAdaptation ); + m_cTEncTop.setAlignCABACBeforeBypass ( m_alignCABACBeforeBypass ); + m_cTEncTop.setTransformSkipLog2MaxSize ( m_transformSkipLog2MaxSize ); + for (UInt signallingModeIndex = 0; signallingModeIndex < NUMBER_OF_RDPCM_SIGNALLING_MODES; signallingModeIndex++) + { + m_cTEncTop.setUseResidualDPCM ( RDPCMSignallingMode(signallingModeIndex), m_useResidualDPCM[signallingModeIndex]); + } + m_cTEncTop.setUseConstrainedIntraPred ( m_bUseConstrainedIntraPred ); + m_cTEncTop.setPCMLog2MinSize ( m_uiPCMLog2MinSize); + m_cTEncTop.setUsePCM ( m_usePCM ); + m_cTEncTop.setPCMLog2MaxSize ( m_pcmLog2MaxSize); + m_cTEncTop.setMaxNumMergeCand ( m_maxNumMergeCand ); + + + //====== Weighted Prediction ======== + m_cTEncTop.setUseWP ( m_useWeightedPred ); + m_cTEncTop.setWPBiPred ( m_useWeightedBiPred ); + //====== Parallel Merge Estimation ======== + m_cTEncTop.setLog2ParallelMergeLevelMinus2 ( m_log2ParallelMergeLevel - 2 ); + + //====== Slice ======== + m_cTEncTop.setSliceMode ( (SliceConstraint) m_sliceMode ); + m_cTEncTop.setSliceArgument ( m_sliceArgument ); + + //====== Dependent Slice ======== + m_cTEncTop.setSliceSegmentMode ( (SliceConstraint) m_sliceSegmentMode ); + m_cTEncTop.setSliceSegmentArgument ( m_sliceSegmentArgument ); + + if(m_sliceMode == NO_SLICES ) + { + m_bLFCrossSliceBoundaryFlag = true; + } + m_cTEncTop.setLFCrossSliceBoundaryFlag ( m_bLFCrossSliceBoundaryFlag ); + m_cTEncTop.setUseSAO ( m_bUseSAO ); + m_cTEncTop.setMaxNumOffsetsPerPic ( m_maxNumOffsetsPerPic); + + m_cTEncTop.setSaoCtuBoundary ( m_saoCtuBoundary); + m_cTEncTop.setPCMInputBitDepthFlag ( m_bPCMInputBitDepthFlag); + m_cTEncTop.setPCMFilterDisableFlag ( m_bPCMFilterDisableFlag); + + m_cTEncTop.setDisableIntraReferenceSmoothing (!m_enableIntraReferenceSmoothing ); + m_cTEncTop.setDecodedPictureHashSEIEnabled ( m_decodedPictureHashSEIEnabled ); + m_cTEncTop.setRecoveryPointSEIEnabled ( m_recoveryPointSEIEnabled ); + m_cTEncTop.setBufferingPeriodSEIEnabled ( m_bufferingPeriodSEIEnabled ); + m_cTEncTop.setPictureTimingSEIEnabled ( m_pictureTimingSEIEnabled ); + m_cTEncTop.setToneMappingInfoSEIEnabled ( m_toneMappingInfoSEIEnabled ); + m_cTEncTop.setTMISEIToneMapId ( m_toneMapId ); + m_cTEncTop.setTMISEIToneMapCancelFlag ( m_toneMapCancelFlag ); + m_cTEncTop.setTMISEIToneMapPersistenceFlag ( m_toneMapPersistenceFlag ); + m_cTEncTop.setTMISEICodedDataBitDepth ( m_toneMapCodedDataBitDepth ); + m_cTEncTop.setTMISEITargetBitDepth ( m_toneMapTargetBitDepth ); + m_cTEncTop.setTMISEIModelID ( m_toneMapModelId ); + m_cTEncTop.setTMISEIMinValue ( m_toneMapMinValue ); + m_cTEncTop.setTMISEIMaxValue ( m_toneMapMaxValue ); + m_cTEncTop.setTMISEISigmoidMidpoint ( m_sigmoidMidpoint ); + m_cTEncTop.setTMISEISigmoidWidth ( m_sigmoidWidth ); + m_cTEncTop.setTMISEIStartOfCodedInterva ( m_startOfCodedInterval ); + m_cTEncTop.setTMISEINumPivots ( m_numPivots ); + m_cTEncTop.setTMISEICodedPivotValue ( m_codedPivotValue ); + m_cTEncTop.setTMISEITargetPivotValue ( m_targetPivotValue ); + m_cTEncTop.setTMISEICameraIsoSpeedIdc ( m_cameraIsoSpeedIdc ); + m_cTEncTop.setTMISEICameraIsoSpeedValue ( m_cameraIsoSpeedValue ); + m_cTEncTop.setTMISEIExposureIndexIdc ( m_exposureIndexIdc ); + m_cTEncTop.setTMISEIExposureIndexValue ( m_exposureIndexValue ); + m_cTEncTop.setTMISEIExposureCompensationValueSignFlag ( m_exposureCompensationValueSignFlag ); + m_cTEncTop.setTMISEIExposureCompensationValueNumerator ( m_exposureCompensationValueNumerator ); + m_cTEncTop.setTMISEIExposureCompensationValueDenomIdc ( m_exposureCompensationValueDenomIdc ); + m_cTEncTop.setTMISEIRefScreenLuminanceWhite ( m_refScreenLuminanceWhite ); + m_cTEncTop.setTMISEIExtendedRangeWhiteLevel ( m_extendedRangeWhiteLevel ); + m_cTEncTop.setTMISEINominalBlackLevelLumaCodeValue ( m_nominalBlackLevelLumaCodeValue ); + m_cTEncTop.setTMISEINominalWhiteLevelLumaCodeValue ( m_nominalWhiteLevelLumaCodeValue ); + m_cTEncTop.setTMISEIExtendedWhiteLevelLumaCodeValue ( m_extendedWhiteLevelLumaCodeValue ); + m_cTEncTop.setChromaSamplingFilterHintEnabled ( m_chromaSamplingFilterSEIenabled ); + m_cTEncTop.setChromaSamplingHorFilterIdc ( m_chromaSamplingHorFilterIdc ); + m_cTEncTop.setChromaSamplingVerFilterIdc ( m_chromaSamplingVerFilterIdc ); + m_cTEncTop.setFramePackingArrangementSEIEnabled ( m_framePackingSEIEnabled ); + m_cTEncTop.setFramePackingArrangementSEIType ( m_framePackingSEIType ); + m_cTEncTop.setFramePackingArrangementSEIId ( m_framePackingSEIId ); + m_cTEncTop.setFramePackingArrangementSEIQuincunx ( m_framePackingSEIQuincunx ); + m_cTEncTop.setFramePackingArrangementSEIInterpretation ( m_framePackingSEIInterpretation ); + m_cTEncTop.setSegmentedRectFramePackingArrangementSEIEnabled ( m_segmentedRectFramePackingSEIEnabled ); + m_cTEncTop.setSegmentedRectFramePackingArrangementSEICancel ( m_segmentedRectFramePackingSEICancel ); + m_cTEncTop.setSegmentedRectFramePackingArrangementSEIType ( m_segmentedRectFramePackingSEIType ); + m_cTEncTop.setSegmentedRectFramePackingArrangementSEIPersistence( m_segmentedRectFramePackingSEIPersistence ); + m_cTEncTop.setDisplayOrientationSEIAngle ( m_displayOrientationSEIAngle ); + m_cTEncTop.setTemporalLevel0IndexSEIEnabled ( m_temporalLevel0IndexSEIEnabled ); + m_cTEncTop.setGradualDecodingRefreshInfoEnabled ( m_gradualDecodingRefreshInfoEnabled ); + m_cTEncTop.setNoDisplaySEITLayer ( m_noDisplaySEITLayer ); + m_cTEncTop.setDecodingUnitInfoSEIEnabled ( m_decodingUnitInfoSEIEnabled ); + m_cTEncTop.setSOPDescriptionSEIEnabled ( m_SOPDescriptionSEIEnabled ); + m_cTEncTop.setScalableNestingSEIEnabled ( m_scalableNestingSEIEnabled ); + m_cTEncTop.setTMCTSSEIEnabled ( m_tmctsSEIEnabled ); + m_cTEncTop.setTimeCodeSEIEnabled ( m_timeCodeSEIEnabled ); + m_cTEncTop.setNumberOfTimeSets ( m_timeCodeSEINumTs ); + for(Int i = 0; i < m_timeCodeSEINumTs; i++) { m_cTEncTop.setTimeSet(m_timeSetArray[i], i); } + m_cTEncTop.setKneeSEIEnabled ( m_kneeSEIEnabled ); + m_cTEncTop.setKneeSEIId ( m_kneeSEIId ); + m_cTEncTop.setKneeSEICancelFlag ( m_kneeSEICancelFlag ); + m_cTEncTop.setKneeSEIPersistenceFlag ( m_kneeSEIPersistenceFlag ); + m_cTEncTop.setKneeSEIInputDrange ( m_kneeSEIInputDrange ); + m_cTEncTop.setKneeSEIInputDispLuminance ( m_kneeSEIInputDispLuminance ); + m_cTEncTop.setKneeSEIOutputDrange ( m_kneeSEIOutputDrange ); + m_cTEncTop.setKneeSEIOutputDispLuminance ( m_kneeSEIOutputDispLuminance ); + m_cTEncTop.setKneeSEINumKneePointsMinus1 ( m_kneeSEINumKneePointsMinus1 ); + m_cTEncTop.setKneeSEIInputKneePoint ( m_kneeSEIInputKneePoint ); + m_cTEncTop.setKneeSEIOutputKneePoint ( m_kneeSEIOutputKneePoint ); + m_cTEncTop.setMasteringDisplaySEI ( m_masteringDisplay ); + + m_cTEncTop.setTileUniformSpacingFlag ( m_tileUniformSpacingFlag ); + m_cTEncTop.setNumColumnsMinus1 ( m_numTileColumnsMinus1 ); + m_cTEncTop.setNumRowsMinus1 ( m_numTileRowsMinus1 ); + if(!m_tileUniformSpacingFlag) + { + m_cTEncTop.setColumnWidth ( m_tileColumnWidth ); + m_cTEncTop.setRowHeight ( m_tileRowHeight ); + } + m_cTEncTop.xCheckGSParameters(); + Int uiTilesCount = (m_numTileRowsMinus1+1) * (m_numTileColumnsMinus1+1); + if(uiTilesCount == 1) + { + m_bLFCrossTileBoundaryFlag = true; + } + m_cTEncTop.setLFCrossTileBoundaryFlag ( m_bLFCrossTileBoundaryFlag ); + m_cTEncTop.setWaveFrontSynchro ( m_iWaveFrontSynchro ); + m_cTEncTop.setWaveFrontSubstreams ( m_iWaveFrontSubstreams ); + m_cTEncTop.setTMVPModeId ( m_TMVPModeId ); + m_cTEncTop.setUseScalingListId ( m_useScalingListId ); + m_cTEncTop.setScalingListFile ( m_scalingListFile ); + m_cTEncTop.setSignHideFlag ( m_signHideFlag); + m_cTEncTop.setUseRateCtrl ( m_RCEnableRateControl ); + m_cTEncTop.setTargetBitrate ( m_RCTargetBitrate ); + m_cTEncTop.setKeepHierBit ( m_RCKeepHierarchicalBit ); + m_cTEncTop.setLCULevelRC ( m_RCLCULevelRC ); + m_cTEncTop.setUseLCUSeparateModel ( m_RCUseLCUSeparateModel ); + m_cTEncTop.setInitialQP ( m_RCInitialQP ); + m_cTEncTop.setForceIntraQP ( m_RCForceIntraQP ); + m_cTEncTop.setTransquantBypassEnableFlag ( m_TransquantBypassEnableFlag ); + m_cTEncTop.setCUTransquantBypassFlagForceValue ( m_CUTransquantBypassFlagForce ); + m_cTEncTop.setCostMode ( m_costMode ); + m_cTEncTop.setUseRecalculateQPAccordingToLambda ( m_recalculateQPAccordingToLambda ); + m_cTEncTop.setUseStrongIntraSmoothing ( m_useStrongIntraSmoothing ); + m_cTEncTop.setActiveParameterSetsSEIEnabled ( m_activeParameterSetsSEIEnabled ); + m_cTEncTop.setVuiParametersPresentFlag ( m_vuiParametersPresentFlag ); + m_cTEncTop.setAspectRatioInfoPresentFlag ( m_aspectRatioInfoPresentFlag); + m_cTEncTop.setAspectRatioIdc ( m_aspectRatioIdc ); + m_cTEncTop.setSarWidth ( m_sarWidth ); + m_cTEncTop.setSarHeight ( m_sarHeight ); + m_cTEncTop.setOverscanInfoPresentFlag ( m_overscanInfoPresentFlag ); + m_cTEncTop.setOverscanAppropriateFlag ( m_overscanAppropriateFlag ); + m_cTEncTop.setVideoSignalTypePresentFlag ( m_videoSignalTypePresentFlag ); + m_cTEncTop.setVideoFormat ( m_videoFormat ); + m_cTEncTop.setVideoFullRangeFlag ( m_videoFullRangeFlag ); + m_cTEncTop.setColourDescriptionPresentFlag ( m_colourDescriptionPresentFlag ); + m_cTEncTop.setColourPrimaries ( m_colourPrimaries ); + m_cTEncTop.setTransferCharacteristics ( m_transferCharacteristics ); + m_cTEncTop.setMatrixCoefficients ( m_matrixCoefficients ); + m_cTEncTop.setChromaLocInfoPresentFlag ( m_chromaLocInfoPresentFlag ); + m_cTEncTop.setChromaSampleLocTypeTopField ( m_chromaSampleLocTypeTopField ); + m_cTEncTop.setChromaSampleLocTypeBottomField ( m_chromaSampleLocTypeBottomField ); + m_cTEncTop.setNeutralChromaIndicationFlag ( m_neutralChromaIndicationFlag ); + m_cTEncTop.setDefaultDisplayWindow ( m_defDispWinLeftOffset, m_defDispWinRightOffset, m_defDispWinTopOffset, m_defDispWinBottomOffset ); + m_cTEncTop.setFrameFieldInfoPresentFlag ( m_frameFieldInfoPresentFlag ); + m_cTEncTop.setPocProportionalToTimingFlag ( m_pocProportionalToTimingFlag ); + m_cTEncTop.setNumTicksPocDiffOneMinus1 ( m_numTicksPocDiffOneMinus1 ); + m_cTEncTop.setBitstreamRestrictionFlag ( m_bitstreamRestrictionFlag ); + m_cTEncTop.setTilesFixedStructureFlag ( m_tilesFixedStructureFlag ); + m_cTEncTop.setMotionVectorsOverPicBoundariesFlag ( m_motionVectorsOverPicBoundariesFlag ); + m_cTEncTop.setMinSpatialSegmentationIdc ( m_minSpatialSegmentationIdc ); + m_cTEncTop.setMaxBytesPerPicDenom ( m_maxBytesPerPicDenom ); + m_cTEncTop.setMaxBitsPerMinCuDenom ( m_maxBitsPerMinCuDenom ); + m_cTEncTop.setLog2MaxMvLengthHorizontal ( m_log2MaxMvLengthHorizontal ); + m_cTEncTop.setLog2MaxMvLengthVertical ( m_log2MaxMvLengthVertical ); +} + +Void TAppEncTop::xCreateLib() +{ + // Video I/O + m_cTVideoIOYuvInputFile.open( m_pchInputFile, false, m_inputBitDepth, m_MSBExtendedBitDepth, m_internalBitDepth ); // read mode + m_cTVideoIOYuvInputFile.skipFrames(m_FrameSkip, m_iSourceWidth - m_aiPad[0], m_iSourceHeight - m_aiPad[1], m_InputChromaFormatIDC); + + if (m_pchReconFile) + { + m_cTVideoIOYuvReconFile.open(m_pchReconFile, true, m_outputBitDepth, m_outputBitDepth, m_internalBitDepth); // write mode + } + + // Neo Decoder + m_cTEncTop.create(); +} + +Void TAppEncTop::xDestroyLib() +{ + // Video I/O + m_cTVideoIOYuvInputFile.close(); + m_cTVideoIOYuvReconFile.close(); + + // Neo Decoder + m_cTEncTop.destroy(); +} + +Void TAppEncTop::xInitLib(Bool isFieldCoding) +{ + m_cTEncTop.init(isFieldCoding); +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** + - create internal class + - initialize internal variable + - until the end of input YUV file, call encoding function in TEncTop class + - delete allocated buffers + - destroy internal class + . + */ +Void TAppEncTop::encode() +{ + fstream bitstreamFile(m_pchBitstreamFile, fstream::binary | fstream::out); + if (!bitstreamFile) + { + fprintf(stderr, "\nfailed to open bitstream file `%s' for writing\n", m_pchBitstreamFile); + exit(EXIT_FAILURE); + } + + TComPicYuv* pcPicYuvOrg = new TComPicYuv; + TComPicYuv* pcPicYuvRec = NULL; + + // initialize internal class & member variables + xInitLibCfg(); + xCreateLib(); + xInitLib(m_isField); + + if (m_verboseLevel) { + printChromaFormat(); + } + + // main encoder loop + Int iNumEncoded = 0; + Bool bEos = false; + + const InputColourSpaceConversion ipCSC = m_inputColourSpaceConvert; + const InputColourSpaceConversion snrCSC = (!m_snrInternalColourSpace) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED; + + list outputAccessUnits; ///< list of access units to write out. is populated by the encoding process + + TComPicYuv cPicYuvTrueOrg; + + // allocate original YUV buffer + if( m_isField ) + { + pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth ); + cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth); + } + else + { + pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth ); + cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth); + } + + while ( !bEos ) + { + // get buffers + xGetBuffer(pcPicYuvRec); + + // read input YUV file + m_cTVideoIOYuvInputFile.read( pcPicYuvOrg, &cPicYuvTrueOrg, ipCSC, m_aiPad, m_InputChromaFormatIDC ); + + // increase number of received frames + m_iFrameRcvd++; + + bEos = (m_isField && (m_iFrameRcvd == (m_framesToBeEncoded >> 1) )) || ( !m_isField && (m_iFrameRcvd == m_framesToBeEncoded) ); + + Bool flush = 0; + // if end of file (which is only detected on a read failure) flush the encoder of any queued pictures + if (m_cTVideoIOYuvInputFile.isEof()) + { + flush = true; + bEos = true; + m_iFrameRcvd--; + m_cTEncTop.setFramesToBeEncoded(m_iFrameRcvd); + } + + // call encoding function for one frame + if ( m_isField ) m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded, m_isTopFieldFirst ); + else m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded ); + + // write bistream to file if necessary + if ( iNumEncoded > 0 ) + { + xWriteOutput(bitstreamFile, iNumEncoded, outputAccessUnits); + outputAccessUnits.clear(); + } + } + + if (m_verboseLevel) { + m_cTEncTop.printSummary(m_isField); + } + + // delete original YUV buffer + pcPicYuvOrg->destroy(); + delete pcPicYuvOrg; + pcPicYuvOrg = NULL; + + // delete used buffers in encoder class + m_cTEncTop.deletePicBuffer(); + cPicYuvTrueOrg.destroy(); + + // delete buffers & classes + xDeleteBuffer(); + xDestroyLib(); + + if (m_verboseLevel) { + printRateSummary(); + } + + return; +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + +/** + - application has picture buffer list with size of GOP + - picture buffer list acts as ring buffer + - end of the list has the latest picture + . + */ +Void TAppEncTop::xGetBuffer( TComPicYuv*& rpcPicYuvRec) +{ + assert( m_iGOPSize > 0 ); + + // org. buffer + if ( m_cListPicYuvRec.size() >= (UInt)m_iGOPSize ) // buffer will be 1 element longer when using field coding, to maintain first field whilst processing second. + { + rpcPicYuvRec = m_cListPicYuvRec.popFront(); + + } + else + { + rpcPicYuvRec = new TComPicYuv; + + rpcPicYuvRec->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth ); + + } + m_cListPicYuvRec.pushBack( rpcPicYuvRec ); +} + +Void TAppEncTop::xDeleteBuffer( ) +{ + TComList::iterator iterPicYuvRec = m_cListPicYuvRec.begin(); + + Int iSize = Int( m_cListPicYuvRec.size() ); + + for ( Int i = 0; i < iSize; i++ ) + { + TComPicYuv* pcPicYuvRec = *(iterPicYuvRec++); + pcPicYuvRec->destroy(); + delete pcPicYuvRec; pcPicYuvRec = NULL; + } + +} + +/** \param iNumEncoded number of encoded frames + */ +Void TAppEncTop::xWriteOutput(std::ostream& bitstreamFile, Int iNumEncoded, const std::list& accessUnits) +{ + const InputColourSpaceConversion ipCSC = (!m_outputInternalColourSpace) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED; + + if (m_isField) + { + //Reinterlace fields + Int i; + TComList::iterator iterPicYuvRec = m_cListPicYuvRec.end(); + list::const_iterator iterBitstream = accessUnits.begin(); + + for ( i = 0; i < iNumEncoded; i++ ) + { + --iterPicYuvRec; + } + + for ( i = 0; i < iNumEncoded/2; i++ ) + { + TComPicYuv* pcPicYuvRecTop = *(iterPicYuvRec++); + TComPicYuv* pcPicYuvRecBottom = *(iterPicYuvRec++); + + if (m_pchReconFile) + { + m_cTVideoIOYuvReconFile.write( pcPicYuvRecTop, pcPicYuvRecBottom, ipCSC, m_confWinLeft, m_confWinRight, m_confWinTop, m_confWinBottom, NUM_CHROMA_FORMAT, m_isTopFieldFirst ); + } + + const AccessUnit& auTop = *(iterBitstream++); + const vector& statsTop = writeAnnexB(bitstreamFile, auTop); + rateStatsAccum(auTop, statsTop); + + const AccessUnit& auBottom = *(iterBitstream++); + const vector& statsBottom = writeAnnexB(bitstreamFile, auBottom); + rateStatsAccum(auBottom, statsBottom); + } + } + else + { + Int i; + + TComList::iterator iterPicYuvRec = m_cListPicYuvRec.end(); + list::const_iterator iterBitstream = accessUnits.begin(); + + for ( i = 0; i < iNumEncoded; i++ ) + { + --iterPicYuvRec; + } + + for ( i = 0; i < iNumEncoded; i++ ) + { + TComPicYuv* pcPicYuvRec = *(iterPicYuvRec++); + if (m_pchReconFile) + { + m_cTVideoIOYuvReconFile.write( pcPicYuvRec, ipCSC, m_confWinLeft, m_confWinRight, m_confWinTop, m_confWinBottom ); + } + + const AccessUnit& au = *(iterBitstream++); + const vector& stats = writeAnnexB(bitstreamFile, au); + rateStatsAccum(au, stats); + } + } +} + +/** + * + */ +Void TAppEncTop::rateStatsAccum(const AccessUnit& au, const std::vector& annexBsizes) +{ + AccessUnit::const_iterator it_au = au.begin(); + vector::const_iterator it_stats = annexBsizes.begin(); + + for (; it_au != au.end(); it_au++, it_stats++) + { + switch ((*it_au)->m_nalUnitType) + { + case NAL_UNIT_CODED_SLICE_TRAIL_R: + case NAL_UNIT_CODED_SLICE_TRAIL_N: + case NAL_UNIT_CODED_SLICE_TSA_R: + case NAL_UNIT_CODED_SLICE_TSA_N: + case NAL_UNIT_CODED_SLICE_STSA_R: + case NAL_UNIT_CODED_SLICE_STSA_N: + case NAL_UNIT_CODED_SLICE_BLA_W_LP: + case NAL_UNIT_CODED_SLICE_BLA_W_RADL: + case NAL_UNIT_CODED_SLICE_BLA_N_LP: + case NAL_UNIT_CODED_SLICE_IDR_W_RADL: + case NAL_UNIT_CODED_SLICE_IDR_N_LP: + case NAL_UNIT_CODED_SLICE_CRA: + case NAL_UNIT_CODED_SLICE_RADL_N: + case NAL_UNIT_CODED_SLICE_RADL_R: + case NAL_UNIT_CODED_SLICE_RASL_N: + case NAL_UNIT_CODED_SLICE_RASL_R: + case NAL_UNIT_VPS: + case NAL_UNIT_SPS: + case NAL_UNIT_PPS: + m_essentialBytes += *it_stats; + break; + default: + break; + } + + m_totalBytes += *it_stats; + } +} + +Void TAppEncTop::printRateSummary() +{ + Double time = (Double) m_iFrameRcvd / m_iFrameRate; + printf("Bytes written to file: %u (%.3f kbps)\n", m_totalBytes, 0.008 * m_totalBytes / time); +#if VERBOSE_RATE + printf("Bytes for SPS/PPS/Slice (Incl. Annex B): %u (%.3f kbps)\n", m_essentialBytes, 0.008 * m_essentialBytes / time); +#endif +} + +Void TAppEncTop::printChromaFormat() +{ + std::cout << std::setw(43) << "Input ChromaFormatIDC = "; + switch (m_InputChromaFormatIDC) + { + case CHROMA_400: std::cout << " 4:0:0"; break; + case CHROMA_420: std::cout << " 4:2:0"; break; + case CHROMA_422: std::cout << " 4:2:2"; break; + case CHROMA_444: std::cout << " 4:4:4"; break; + default: + std::cerr << "Invalid"; + exit(1); + } + std::cout << std::endl; + + std::cout << std::setw(43) << "Output (internal) ChromaFormatIDC = "; + switch (m_cTEncTop.getChromaFormatIdc()) + { + case CHROMA_400: std::cout << " 4:0:0"; break; + case CHROMA_420: std::cout << " 4:2:0"; break; + case CHROMA_422: std::cout << " 4:2:2"; break; + case CHROMA_444: std::cout << " 4:4:4"; break; + default: + std::cerr << "Invalid"; + exit(1); + } + std::cout << "\n" << std::endl; +} + +//! \} diff --git a/jctvc/TAppEncTop.h b/jctvc/TAppEncTop.h new file mode 100644 index 0000000..eea416c --- /dev/null +++ b/jctvc/TAppEncTop.h @@ -0,0 +1,103 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TAppEncTop.h + \brief Encoder application class (header) +*/ + +#ifndef __TAPPENCTOP__ +#define __TAPPENCTOP__ + +#include +#include + +#include "TLibEncoder/TEncTop.h" +#include "TLibVideoIO/TVideoIOYuv.h" +#include "TLibCommon/AccessUnit.h" +#include "TAppEncCfg.h" + +//! \ingroup TAppEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// encoder application class +class TAppEncTop : public TAppEncCfg +{ +private: + // class interface + TEncTop m_cTEncTop; ///< encoder class + TVideoIOYuv m_cTVideoIOYuvInputFile; ///< input YUV file + TVideoIOYuv m_cTVideoIOYuvReconFile; ///< output reconstruction file + + TComList m_cListPicYuvRec; ///< list of reconstruction YUV files + + Int m_iFrameRcvd; ///< number of received frames + + UInt m_essentialBytes; + UInt m_totalBytes; + +protected: + // initialization + Void xCreateLib (); ///< create files & encoder class + Void xInitLibCfg (); ///< initialize internal variables + Void xInitLib (Bool isFieldCoding); ///< initialize encoder class + Void xDestroyLib (); ///< destroy encoder class + + /// obtain required buffers + Void xGetBuffer(TComPicYuv*& rpcPicYuvRec); + + /// delete allocated buffers + Void xDeleteBuffer (); + + // file I/O + Void xWriteOutput(std::ostream& bitstreamFile, Int iNumEncoded, const std::list& accessUnits); ///< write bitstream to file + Void rateStatsAccum(const AccessUnit& au, const std::vector& stats); + Void printRateSummary(); + Void printChromaFormat(); + +public: + TAppEncTop(); + virtual ~TAppEncTop(); + + Void encode (); ///< main encoding function + TEncTop& getTEncTop () { return m_cTEncTop; } ///< return encoder class pointer reference + +};// END CLASS DEFINITION TAppEncTop + +//! \} + +#endif // __TAPPENCTOP__ + diff --git a/jctvc/TLibCommon/AccessUnit.h b/jctvc/TLibCommon/AccessUnit.h new file mode 100644 index 0000000..ba193e2 --- /dev/null +++ b/jctvc/TLibCommon/AccessUnit.h @@ -0,0 +1,76 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + \file AccessUnit.h + \brief Access Unit class (header) + */ + +#pragma once + +#ifndef __ACCESSUNIT__ +#define __ACCESSUNIT__ + +#include +#include "NAL.h" + +//! \ingroup TLibCommon +//! \{ + +/** + * An AccessUnit is a list of one or more NAL units, according to the + * working draft. All NAL units within the object belong to the same + * access unit. + * + * NALUnits held in the AccessUnit list are in EBSP format. Attempting + * to insert an OutputNALUnit into the access unit will automatically cause + * the nalunit to have its headers written and anti-emulation performed. + * + * The AccessUnit owns all pointers stored within. Destroying the + * AccessUnit will delete all contained objects. + */ +class AccessUnit : public std::list // NOTE: Should not inherit from STL. +{ +public: + ~AccessUnit() + { + for (AccessUnit::iterator it = this->begin(); it != this->end(); it++) + { + delete *it; + } + } +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/CommonDef.h b/jctvc/TLibCommon/CommonDef.h new file mode 100644 index 0000000..828b3a4 --- /dev/null +++ b/jctvc/TLibCommon/CommonDef.h @@ -0,0 +1,299 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file CommonDef.h + \brief Defines constants, macros and tool parameters +*/ + +#ifndef __COMMONDEF__ +#define __COMMONDEF__ + +#include +#include +#include + +#if _MSC_VER > 1000 +// disable "signed and unsigned mismatch" +#pragma warning( disable : 4018 ) +// disable Bool coercion "performance warning" +#pragma warning( disable : 4800 ) +#endif // _MSC_VER > 1000 +#include "TypeDef.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Version information +// ==================================================================================================================== + +#define NV_VERSION "16.2" ///< Current software version + +// ==================================================================================================================== +// Platform information +// ==================================================================================================================== + +#ifdef __GNUC__ +#define NVM_COMPILEDBY "[GCC %d.%d.%d]", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ +#ifdef __IA64__ +#define NVM_ONARCH "[on 64-bit] " +#else +#define NVM_ONARCH "[on 32-bit] " +#endif +#endif + +#ifdef __INTEL_COMPILER +#define NVM_COMPILEDBY "[ICC %d]", __INTEL_COMPILER +#elif _MSC_VER +#define NVM_COMPILEDBY "[VS %d]", _MSC_VER +#endif + +#ifndef NVM_COMPILEDBY +#define NVM_COMPILEDBY "[Unk-CXX]" +#endif + +#ifdef _WIN32 +#define NVM_ONOS "[Windows]" +#elif __linux +#define NVM_ONOS "[Linux]" +#elif __CYGWIN__ +#define NVM_ONOS "[Cygwin]" +#elif __APPLE__ +#define NVM_ONOS "[Mac OS X]" +#else +#define NVM_ONOS "[Unk-OS]" +#endif + +#define NVM_BITS "[%d bit] ", (sizeof(Void*) == 8 ? 64 : 32) ///< used for checking 64-bit O/S + +#ifndef NULL +#define NULL 0 +#endif + +// ==================================================================================================================== +// Common constants +// ==================================================================================================================== + +#define _SUMMARY_OUT_ 0 ///< print-out PSNR results of all slices to summary.txt +#define _SUMMARY_PIC_ 0 ///< print-out PSNR results for each slice type to summary.txt + +#define MAX_GOP 64 ///< max. value of hierarchical GOP size + +#define MAX_NUM_REF_PICS 16 ///< max. number of pictures used for reference +#define MAX_NUM_REF 16 ///< max. number of entries in picture reference list + +#define MAX_UINT 0xFFFFFFFFU ///< max. value of unsigned 32-bit integer +#define MAX_INT 2147483647 ///< max. value of signed 32-bit integer +#define MAX_INT64 0x7FFFFFFFFFFFFFFFLL ///< max. value of signed 64-bit integer +#if RExt__HIGH_BIT_DEPTH_SUPPORT +#define MAX_INTERMEDIATE_INT MAX_INT64 +#else +#define MAX_INTERMEDIATE_INT MAX_INT +#endif + +#define MAX_DOUBLE 1.7e+308 ///< max. value of Double-type value + +#define MIN_QP 0 +#define MAX_QP 51 + +#define NOT_VALID -1 + +// ==================================================================================================================== +// Macro functions +// ==================================================================================================================== + +extern Int g_bitDepth[MAX_NUM_CHANNEL_TYPE]; + +template inline T Clip3 (const T minVal, const T maxVal, const T a) { return std::min (std::max (minVal, a) , maxVal); } ///< general min/max clip +template inline T ClipBD(const T x, const Int bitDepth) { return Clip3(T(0), T((1 << bitDepth)-1), x); } +template inline T Clip (const T x, const ChannelType type) { return ClipBD(x, g_bitDepth[type]); } + +template inline Void Check3( T minVal, T maxVal, T a) +{ + if ((a > maxVal) || (a < minVal)) + { + std::cerr << "ERROR: Range check " << minVal << " >= " << a << " <= " << maxVal << " failed" << std::endl; + assert(false); + exit(1); + } +} ///< general min/max clip + +#define DATA_ALIGN 1 ///< use 32-bit aligned malloc/free +#if DATA_ALIGN && _WIN32 && ( _MSC_VER > 1300 ) +#define xMalloc( type, len ) _aligned_malloc( sizeof(type)*(len), 32 ) +#define xFree( ptr ) _aligned_free ( ptr ) +#else +#define xMalloc( type, len ) malloc ( sizeof(type)*(len) ) +#define xFree( ptr ) free ( ptr ) +#endif + +#define FATAL_ERROR_0(MESSAGE, EXITCODE) \ +{ \ + printf(MESSAGE); \ + exit(EXITCODE); \ +} + +template inline ValueType leftShift (const ValueType value, const Int shift) { return (shift >= 0) ? ( value << shift) : ( value >> -shift); } +template inline ValueType rightShift (const ValueType value, const Int shift) { return (shift >= 0) ? ( value >> shift) : ( value << -shift); } +template inline ValueType leftShift_round (const ValueType value, const Int shift) { return (shift >= 0) ? ( value << shift) : ((value + (ValueType(1) << (-shift - 1))) >> -shift); } +template inline ValueType rightShift_round(const ValueType value, const Int shift) { return (shift >= 0) ? ((value + (ValueType(1) << (shift - 1))) >> shift) : ( value << -shift); } +#if O0043_BEST_EFFORT_DECODING +// when shift = 0, returns value +// when shift = 1, (value + 0 + value[1]) >> 1 +// when shift = 2, (value + 1 + value[2]) >> 2 +// when shift = 3, (value + 3 + value[3]) >> 3 +template inline ValueType rightShiftEvenRounding(const ValueType value, const UInt shift) { return (shift == 0) ? value : ((value + (1<<(shift-1))-1 + ((value>>shift)&1)) >> shift) ; } +#endif + +// ==================================================================================================================== +// Coding tool configuration +// ==================================================================================================================== + +// AMVP: advanced motion vector prediction +#define AMVP_MAX_NUM_CANDS 2 ///< max number of final candidates +#define AMVP_MAX_NUM_CANDS_MEM 3 ///< max number of candidates +// MERGE +#define MRG_MAX_NUM_CANDS 5 + +// Reference memory management +#define DYN_REF_FREE 0 ///< dynamic free of reference memories + +// Explicit temporal layer QP offset +#define MAX_TLAYER 7 ///< max number of temporal layer +#define HB_LAMBDA_FOR_LDC 1 ///< use of B-style lambda for non-key pictures in low-delay mode + +// Fast estimation of generalized B in low-delay mode +#define GPB_SIMPLE 1 ///< Simple GPB mode +#if GPB_SIMPLE +#define GPB_SIMPLE_UNI 1 ///< Simple mode for uni-direction +#endif + +// Fast ME using smoother MV assumption +#define FASTME_SMOOTHER_MV 1 ///< reduce ME time using faster option + +// Adaptive search range depending on POC difference +#define ADAPT_SR_SCALE 1 ///< division factor for adaptive search range + +#define CLIP_TO_709_RANGE 0 + +// Early-skip threshold (encoder) +#define EARLY_SKIP_THRES 1.50 ///< if RD < thres*avg[BestSkipRD] + + +#define MAX_CHROMA_FORMAT_IDC 3 + +// TODO: Existing names used for the different NAL unit types can be altered to better reflect the names in the spec. +// However, the names in the spec are not yet stable at this point. Once the names are stable, a cleanup +// effort can be done without use of macros to alter the names used to indicate the different NAL unit types. +enum NalUnitType +{ + NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0 + NAL_UNIT_CODED_SLICE_TRAIL_R, // 1 + + NAL_UNIT_CODED_SLICE_TSA_N, // 2 + NAL_UNIT_CODED_SLICE_TSA_R, // 3 + + NAL_UNIT_CODED_SLICE_STSA_N, // 4 + NAL_UNIT_CODED_SLICE_STSA_R, // 5 + + NAL_UNIT_CODED_SLICE_RADL_N, // 6 + NAL_UNIT_CODED_SLICE_RADL_R, // 7 + + NAL_UNIT_CODED_SLICE_RASL_N, // 8 + NAL_UNIT_CODED_SLICE_RASL_R, // 9 + + NAL_UNIT_RESERVED_VCL_N10, + NAL_UNIT_RESERVED_VCL_R11, + NAL_UNIT_RESERVED_VCL_N12, + NAL_UNIT_RESERVED_VCL_R13, + NAL_UNIT_RESERVED_VCL_N14, + NAL_UNIT_RESERVED_VCL_R15, + + NAL_UNIT_CODED_SLICE_BLA_W_LP, // 16 + NAL_UNIT_CODED_SLICE_BLA_W_RADL, // 17 + NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18 + NAL_UNIT_CODED_SLICE_IDR_W_RADL, // 19 + NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20 + NAL_UNIT_CODED_SLICE_CRA, // 21 + NAL_UNIT_RESERVED_IRAP_VCL22, + NAL_UNIT_RESERVED_IRAP_VCL23, + + NAL_UNIT_RESERVED_VCL24, + NAL_UNIT_RESERVED_VCL25, + NAL_UNIT_RESERVED_VCL26, + NAL_UNIT_RESERVED_VCL27, + NAL_UNIT_RESERVED_VCL28, + NAL_UNIT_RESERVED_VCL29, + NAL_UNIT_RESERVED_VCL30, + NAL_UNIT_RESERVED_VCL31, + + NAL_UNIT_VPS, // 32 + NAL_UNIT_SPS, // 33 + NAL_UNIT_PPS, // 34 + NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35 + NAL_UNIT_EOS, // 36 + NAL_UNIT_EOB, // 37 + NAL_UNIT_FILLER_DATA, // 38 + NAL_UNIT_PREFIX_SEI, // 39 + NAL_UNIT_SUFFIX_SEI, // 40 + + NAL_UNIT_RESERVED_NVCL41, + NAL_UNIT_RESERVED_NVCL42, + NAL_UNIT_RESERVED_NVCL43, + NAL_UNIT_RESERVED_NVCL44, + NAL_UNIT_RESERVED_NVCL45, + NAL_UNIT_RESERVED_NVCL46, + NAL_UNIT_RESERVED_NVCL47, + NAL_UNIT_UNSPECIFIED_48, + NAL_UNIT_UNSPECIFIED_49, + NAL_UNIT_UNSPECIFIED_50, + NAL_UNIT_UNSPECIFIED_51, + NAL_UNIT_UNSPECIFIED_52, + NAL_UNIT_UNSPECIFIED_53, + NAL_UNIT_UNSPECIFIED_54, + NAL_UNIT_UNSPECIFIED_55, + NAL_UNIT_UNSPECIFIED_56, + NAL_UNIT_UNSPECIFIED_57, + NAL_UNIT_UNSPECIFIED_58, + NAL_UNIT_UNSPECIFIED_59, + NAL_UNIT_UNSPECIFIED_60, + NAL_UNIT_UNSPECIFIED_61, + NAL_UNIT_UNSPECIFIED_62, + NAL_UNIT_UNSPECIFIED_63, + NAL_UNIT_INVALID, +}; + +//! \} + +#endif // end of #ifndef __COMMONDEF__ + diff --git a/jctvc/TLibCommon/ContextModel.cpp b/jctvc/TLibCommon/ContextModel.cpp new file mode 100644 index 0000000..c1278c0 --- /dev/null +++ b/jctvc/TLibCommon/ContextModel.cpp @@ -0,0 +1,129 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file ContextModel.cpp + \brief context model class +*/ + +#include + +#include "ContextModel.h" + +using namespace std; +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** + - initialize context model with respect to QP and initialization value + . + \param qp input QP value + \param initValue 8 bit initialization value + */ +Void ContextModel::init( Int qp, Int initValue ) +{ + qp = Clip3(0, 51, qp); + + Int slope = (initValue>>4)*5 - 45; + Int offset = ((initValue&15)<<3)-16; + Int initState = min( max( 1, ( ( ( slope * qp ) >> 4 ) + offset ) ), 126 ); + UInt mpState = (initState >= 64 ); + m_ucState = ( (mpState? (initState - 64):(63 - initState)) <<1) + mpState; +} + +const UChar ContextModel::m_aucNextStateMPS[ ContextModel::m_totalStates ] = +{ + 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, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 124, 125, 126, 127 +}; + +const UChar ContextModel::m_aucNextStateLPS[ ContextModel::m_totalStates ] = +{ + 1, 0, 0, 1, 2, 3, 4, 5, 4, 5, 8, 9, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 18, 19, 22, 23, 22, 23, 24, 25, + 26, 27, 26, 27, 30, 31, 30, 31, 32, 33, 32, 33, 36, 37, 36, 37, + 38, 39, 38, 39, 42, 43, 42, 43, 44, 45, 44, 45, 46, 47, 48, 49, + 48, 49, 50, 51, 52, 53, 52, 53, 54, 55, 54, 55, 56, 57, 58, 59, + 58, 59, 60, 61, 60, 61, 60, 61, 62, 63, 64, 65, 64, 65, 66, 67, + 66, 67, 66, 67, 68, 69, 68, 69, 70, 71, 70, 71, 70, 71, 72, 73, + 72, 73, 72, 73, 74, 75, 74, 75, 74, 75, 76, 77, 76, 77, 126, 127 +}; + +#if FAST_BIT_EST +UChar ContextModel::m_nextState[ ContextModel::m_totalStates ][2 /*MPS = [0|1]*/]; + +Void ContextModel::buildNextStateTable() +{ + for (Int i = 0; i < ContextModel::m_totalStates; i++) + { + for (Int j = 0; j < 2; j++) + { + m_nextState[i][j] = ((i&1) == j) ? m_aucNextStateMPS[i] : m_aucNextStateLPS[i]; + } + } +} +#endif + +const Int ContextModel::m_entropyBits[ ContextModel::m_totalStates ] = +{ +#if FAST_BIT_EST + // Corrected table, most notably for last state + 0x07b23, 0x085f9, 0x074a0, 0x08cbc, 0x06ee4, 0x09354, 0x067f4, 0x09c1b, 0x060b0, 0x0a62a, 0x05a9c, 0x0af5b, 0x0548d, 0x0b955, 0x04f56, 0x0c2a9, + 0x04a87, 0x0cbf7, 0x045d6, 0x0d5c3, 0x04144, 0x0e01b, 0x03d88, 0x0e937, 0x039e0, 0x0f2cd, 0x03663, 0x0fc9e, 0x03347, 0x10600, 0x03050, 0x10f95, + 0x02d4d, 0x11a02, 0x02ad3, 0x12333, 0x0286e, 0x12cad, 0x02604, 0x136df, 0x02425, 0x13f48, 0x021f4, 0x149c4, 0x0203e, 0x1527b, 0x01e4d, 0x15d00, + 0x01c99, 0x166de, 0x01b18, 0x17017, 0x019a5, 0x17988, 0x01841, 0x18327, 0x016df, 0x18d50, 0x015d9, 0x19547, 0x0147c, 0x1a083, 0x0138e, 0x1a8a3, + 0x01251, 0x1b418, 0x01166, 0x1bd27, 0x01068, 0x1c77b, 0x00f7f, 0x1d18e, 0x00eda, 0x1d91a, 0x00e19, 0x1e254, 0x00d4f, 0x1ec9a, 0x00c90, 0x1f6e0, + 0x00c01, 0x1fef8, 0x00b5f, 0x208b1, 0x00ab6, 0x21362, 0x00a15, 0x21e46, 0x00988, 0x2285d, 0x00934, 0x22ea8, 0x008a8, 0x239b2, 0x0081d, 0x24577, + 0x007c9, 0x24ce6, 0x00763, 0x25663, 0x00710, 0x25e8f, 0x006a0, 0x26a26, 0x00672, 0x26f23, 0x005e8, 0x27ef8, 0x005ba, 0x284b5, 0x0055e, 0x29057, + 0x0050c, 0x29bab, 0x004c1, 0x2a674, 0x004a7, 0x2aa5e, 0x0046f, 0x2b32f, 0x0041f, 0x2c0ad, 0x003e7, 0x2ca8d, 0x003ba, 0x2d323, 0x0010c, 0x3bfbb +#else + 0x08000, 0x08000, 0x076da, 0x089a0, 0x06e92, 0x09340, 0x0670a, 0x09cdf, 0x06029, 0x0a67f, 0x059dd, 0x0b01f, 0x05413, 0x0b9bf, 0x04ebf, 0x0c35f, + 0x049d3, 0x0ccff, 0x04546, 0x0d69e, 0x0410d, 0x0e03e, 0x03d22, 0x0e9de, 0x0397d, 0x0f37e, 0x03619, 0x0fd1e, 0x032ee, 0x106be, 0x02ffa, 0x1105d, + 0x02d37, 0x119fd, 0x02aa2, 0x1239d, 0x02836, 0x12d3d, 0x025f2, 0x136dd, 0x023d1, 0x1407c, 0x021d2, 0x14a1c, 0x01ff2, 0x153bc, 0x01e2f, 0x15d5c, + 0x01c87, 0x166fc, 0x01af7, 0x1709b, 0x0197f, 0x17a3b, 0x0181d, 0x183db, 0x016d0, 0x18d7b, 0x01595, 0x1971b, 0x0146c, 0x1a0bb, 0x01354, 0x1aa5a, + 0x0124c, 0x1b3fa, 0x01153, 0x1bd9a, 0x01067, 0x1c73a, 0x00f89, 0x1d0da, 0x00eb7, 0x1da79, 0x00df0, 0x1e419, 0x00d34, 0x1edb9, 0x00c82, 0x1f759, + 0x00bda, 0x200f9, 0x00b3c, 0x20a99, 0x00aa5, 0x21438, 0x00a17, 0x21dd8, 0x00990, 0x22778, 0x00911, 0x23118, 0x00898, 0x23ab8, 0x00826, 0x24458, + 0x007ba, 0x24df7, 0x00753, 0x25797, 0x006f2, 0x26137, 0x00696, 0x26ad7, 0x0063f, 0x27477, 0x005ed, 0x27e17, 0x0059f, 0x287b6, 0x00554, 0x29156, + 0x0050e, 0x29af6, 0x004cc, 0x2a497, 0x0048d, 0x2ae35, 0x00451, 0x2b7d6, 0x00418, 0x2c176, 0x003e2, 0x2cb15, 0x003af, 0x2d4b5, 0x0037f, 0x2de55 +#endif +}; +//! \} diff --git a/jctvc/TLibCommon/ContextModel.h b/jctvc/TLibCommon/ContextModel.h new file mode 100644 index 0000000..0d0a0b8 --- /dev/null +++ b/jctvc/TLibCommon/ContextModel.h @@ -0,0 +1,108 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** \file ContextModel.h + \brief context model class (header) +*/ + +#ifndef __CONTEXTMODEL__ +#define __CONTEXTMODEL__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "CommonDef.h" +#include "TComRom.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// context model class +class ContextModel +{ +public: + ContextModel () { m_ucState = 0; m_binsCoded = 0; } + ~ContextModel () {} + + UChar getState () { return ( m_ucState >> 1 ); } ///< get current state + UChar getMps () { return ( m_ucState & 1 ); } ///< get curret MPS + Void setStateAndMps( UChar ucState, UChar ucMPS) { m_ucState = (ucState << 1) + ucMPS; } ///< set state and MPS + + Void init ( Int qp, Int initValue ); ///< initialize state with initial probability + + Void updateLPS () + { + m_ucState = m_aucNextStateLPS[ m_ucState ]; + } + + Void updateMPS () + { + m_ucState = m_aucNextStateMPS[ m_ucState ]; + } + + Int getEntropyBits(Short val) { return m_entropyBits[m_ucState ^ val]; } + +#if FAST_BIT_EST + Void update( Int binVal ) + { + m_ucState = m_nextState[m_ucState][binVal]; + } + static Void buildNextStateTable(); + static Int getEntropyBitsTrm( Int val ) { return m_entropyBits[126 ^ val]; } +#endif + Void setBinsCoded(UInt val) { m_binsCoded = val; } + UInt getBinsCoded() { return m_binsCoded; } + +private: + UChar m_ucState; ///< internal state variable + + static const UInt m_totalStates = (1 << CONTEXT_STATE_BITS) * 2; //*2 for MPS = [0|1] + static const UChar m_aucNextStateMPS[m_totalStates]; + static const UChar m_aucNextStateLPS[m_totalStates]; + static const Int m_entropyBits [m_totalStates]; +#if FAST_BIT_EST + static UChar m_nextState[m_totalStates][2 /*MPS = [0|1]*/]; +#endif + UInt m_binsCoded; +}; + +//! \} + +#endif + diff --git a/jctvc/TLibCommon/ContextModel3DBuffer.cpp b/jctvc/TLibCommon/ContextModel3DBuffer.cpp new file mode 100644 index 0000000..b110632 --- /dev/null +++ b/jctvc/TLibCommon/ContextModel3DBuffer.cpp @@ -0,0 +1,120 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file ContextModel3DBuffer.cpp + \brief context model 3D buffer class +*/ + +#include "ContextModel3DBuffer.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / initialization / destroy +// ==================================================================================================================== + +ContextModel3DBuffer::ContextModel3DBuffer( UInt uiSizeZ, UInt uiSizeY, UInt uiSizeX, ContextModel *basePtr, Int &count ) +: m_sizeX ( uiSizeX ) +, m_sizeXY ( uiSizeX * uiSizeY ) +, m_sizeXYZ( uiSizeX * uiSizeY * uiSizeZ ) +{ + // allocate 3D buffer + m_contextModel = basePtr; + count += m_sizeXYZ; +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** + * Initialize 3D buffer with respect to slicetype, QP and given initial probability table + * + * \param eSliceType slice type + * \param iQp input QP value + * \param psCtxModel given probability table + */ +Void ContextModel3DBuffer::initBuffer( SliceType sliceType, Int qp, UChar* ctxModel ) +{ + ctxModel += sliceType * m_sizeXYZ; + + for ( Int n = 0; n < m_sizeXYZ; n++ ) + { + m_contextModel[ n ].init( qp, ctxModel[ n ] ); + m_contextModel[ n ].setBinsCoded( 0 ); + } +} + +/** + * Calculate the cost of choosing a probability table based on the current probability of CABAC at encoder + * + * \param sliceType slice type + * \param qp input QP value + * \param ctxModel given probability table + */ +UInt ContextModel3DBuffer::calcCost( SliceType sliceType, Int qp, UChar* ctxModel ) +{ + UInt cost = 0; + ctxModel += sliceType * m_sizeXYZ; + + for ( Int n = 0; n < m_sizeXYZ; n++ ) + { + ContextModel tmpContextModel; + tmpContextModel.init( qp, ctxModel[ n ] ); + + // Map the 64 CABAC states to their corresponding probability values + static Double aStateToProbLPS[] = {0.50000000, 0.47460857, 0.45050660, 0.42762859, 0.40591239, 0.38529900, 0.36573242, 0.34715948, 0.32952974, 0.31279528, 0.29691064, 0.28183267, 0.26752040, 0.25393496, 0.24103941, 0.22879875, 0.21717969, 0.20615069, 0.19568177, 0.18574449, 0.17631186, 0.16735824, 0.15885931, 0.15079198, 0.14313433, 0.13586556, 0.12896592, 0.12241667, 0.11620000, 0.11029903, 0.10469773, 0.09938088, 0.09433404, 0.08954349, 0.08499621, 0.08067986, 0.07658271, 0.07269362, 0.06900203, 0.06549791, 0.06217174, 0.05901448, 0.05601756, 0.05317283, 0.05047256, 0.04790942, 0.04547644, 0.04316702, 0.04097487, 0.03889405, 0.03691890, 0.03504406, 0.03326442, 0.03157516, 0.02997168, 0.02844963, 0.02700488, 0.02563349, 0.02433175, 0.02309612, 0.02192323, 0.02080991, 0.01975312, 0.01875000}; + + Double probLPS = aStateToProbLPS[ m_contextModel[ n ].getState() ]; + Double prob0, prob1; + if (m_contextModel[ n ].getMps()==1) + { + prob0 = probLPS; + prob1 = 1.0-prob0; + } + else + { + prob1 = probLPS; + prob0 = 1.0-prob1; + } + + if (m_contextModel[ n ].getBinsCoded()>0) + { + cost += (UInt) (prob0 * tmpContextModel.getEntropyBits( 0 ) + prob1 * tmpContextModel.getEntropyBits( 1 )); + } + } + + return cost; +} +//! \} diff --git a/jctvc/TLibCommon/ContextModel3DBuffer.h b/jctvc/TLibCommon/ContextModel3DBuffer.h new file mode 100644 index 0000000..5b5584f --- /dev/null +++ b/jctvc/TLibCommon/ContextModel3DBuffer.h @@ -0,0 +1,98 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file ContextModel3DBuffer.h + \brief context model 3D buffer class (header) +*/ + +#ifndef __CONTEXTMODEL3DBUFFER__ +#define __CONTEXTMODEL3DBUFFER__ + +#include +#include +#include + +#include "CommonDef.h" +#include "ContextModel.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// context model 3D buffer class +class ContextModel3DBuffer +{ +protected: + ContextModel* m_contextModel; ///< array of context models + const UInt m_sizeX; ///< X size of 3D buffer + const UInt m_sizeXY; ///< X times Y size of 3D buffer + const UInt m_sizeXYZ; ///< total size of 3D buffer + +public: + ContextModel3DBuffer ( UInt uiSizeZ, UInt uiSizeY, UInt uiSizeX, ContextModel *basePtr, Int &count ); + ~ContextModel3DBuffer () {} + + // access functions + ContextModel& get( UInt uiZ, UInt uiY, UInt uiX ) + { + return m_contextModel[ uiZ * m_sizeXY + uiY * m_sizeX + uiX ]; + } + ContextModel* get( UInt uiZ, UInt uiY ) + { + return &m_contextModel[ uiZ * m_sizeXY + uiY * m_sizeX ]; + } + ContextModel* get( UInt uiZ ) + { + return &m_contextModel[ uiZ * m_sizeXY ]; + } + + // initialization & copy functions + Void initBuffer( SliceType eSliceType, Int iQp, UChar* ctxModel ); ///< initialize 3D buffer by slice type & QP + + UInt calcCost( SliceType sliceType, Int qp, UChar* ctxModel ); ///< determine cost of choosing a probability table based on current probabilities + /** copy from another buffer + * \param src buffer to copy from + */ + Void copyFrom( const ContextModel3DBuffer* src ) + { + assert( m_sizeXYZ == src->m_sizeXYZ ); + ::memcpy( m_contextModel, src->m_contextModel, sizeof(ContextModel) * m_sizeXYZ ); + } +}; + +//! \} + +#endif // _HM_CONTEXT_MODEL_3DBUFFER_H_ diff --git a/jctvc/TLibCommon/ContextTables.h b/jctvc/TLibCommon/ContextTables.h new file mode 100644 index 0000000..c5cebf6 --- /dev/null +++ b/jctvc/TLibCommon/ContextTables.h @@ -0,0 +1,502 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file ContextTables.h + \brief Defines constants and tables for SBAC + \todo number of context models is not matched to actual use, should be fixed +*/ + +#ifndef __CONTEXTTABLES__ +#define __CONTEXTTABLES__ + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +#define MAX_NUM_CTX_MOD 512 ///< maximum number of supported contexts + +#define NUM_SPLIT_FLAG_CTX 3 ///< number of context models for split flag +#define NUM_SKIP_FLAG_CTX 3 ///< number of context models for skip flag + +#define NUM_MERGE_FLAG_EXT_CTX 1 ///< number of context models for merge flag of merge extended +#define NUM_MERGE_IDX_EXT_CTX 1 ///< number of context models for merge index of merge extended + +#define NUM_PART_SIZE_CTX 4 ///< number of context models for partition size +#define NUM_PRED_MODE_CTX 1 ///< number of context models for prediction mode + +#define NUM_ADI_CTX 1 ///< number of context models for intra prediction + +#define NUM_CHROMA_PRED_CTX 2 ///< number of context models for intra prediction (chroma) +#define NUM_INTER_DIR_CTX 5 ///< number of context models for inter prediction direction +#define NUM_MV_RES_CTX 2 ///< number of context models for motion vector difference +#define NUM_CHROMA_QP_ADJ_FLAG_CTX 1 ///< number of context models for chroma_qp_adjustment_flag +#define NUM_CHROMA_QP_ADJ_IDC_CTX 1 ///< number of context models for chroma_qp_adjustment_idc + +#define NUM_REF_NO_CTX 2 ///< number of context models for reference index +#define NUM_TRANS_SUBDIV_FLAG_CTX 3 ///< number of context models for transform subdivision flags +#define NUM_QT_ROOT_CBF_CTX 1 ///< number of context models for QT ROOT CBF +#define NUM_DELTA_QP_CTX 3 ///< number of context models for dQP + +#define NUM_SIG_CG_FLAG_CTX 2 ///< number of context models for MULTI_LEVEL_SIGNIFICANCE +#define NUM_EXPLICIT_RDPCM_FLAG_CTX 1 ///< number of context models for the flag which specifies whether to use RDPCM on inter coded residues +#define NUM_EXPLICIT_RDPCM_DIR_CTX 1 ///< number of context models for the flag which specifies which RDPCM direction is used on inter coded residues + +//-------------------------------------------------------------------------------------------------- + +// context size definitions for significance map + +#define NUM_SIG_FLAG_CTX_LUMA 28 ///< number of context models for luma sig flag +#define NUM_SIG_FLAG_CTX_CHROMA 16 ///< number of context models for chroma sig flag + +// |----Luma-----| |---Chroma----| +static const UInt significanceMapContextSetStart [MAX_NUM_CHANNEL_TYPE][CONTEXT_NUMBER_OF_TYPES] = { {0, 9, 21, 27}, {0, 9, 12, 15} }; +static const UInt significanceMapContextSetSize [MAX_NUM_CHANNEL_TYPE][CONTEXT_NUMBER_OF_TYPES] = { {9, 12, 6, 1}, {9, 3, 3, 1} }; +static const UInt nonDiagonalScan8x8ContextOffset [MAX_NUM_CHANNEL_TYPE] = { 6, 0 }; +static const UInt notFirstGroupNeighbourhoodContextOffset[MAX_NUM_CHANNEL_TYPE] = { 3, 0 }; + +//------------------ + +#define NEIGHBOURHOOD_00_CONTEXT_1_THRESHOLD_4x4 3 +#define NEIGHBOURHOOD_00_CONTEXT_2_THRESHOLD_4x4 1 + +//------------------ + +#define FIRST_SIG_FLAG_CTX_LUMA 0 +#define FIRST_SIG_FLAG_CTX_CHROMA (FIRST_SIG_FLAG_CTX_LUMA + NUM_SIG_FLAG_CTX_LUMA) + +#define NUM_SIG_FLAG_CTX (NUM_SIG_FLAG_CTX_LUMA + NUM_SIG_FLAG_CTX_CHROMA) ///< number of context models for sig flag + +//-------------------------------------------------------------------------------------------------- + +// context size definitions for last significant coefficient position + +#define NUM_CTX_LAST_FLAG_SETS 2 + +#define NUM_CTX_LAST_FLAG_XY 15 ///< number of context models for last coefficient position + +//-------------------------------------------------------------------------------------------------- + +// context size definitions for greater-than-one and greater-than-two maps + +#define NUM_ONE_FLAG_CTX_PER_SET 4 ///< number of context models for greater than 1 flag in a set +#define NUM_ABS_FLAG_CTX_PER_SET 1 ///< number of context models for greater than 2 flag in a set + +//------------------ + +#define NUM_CTX_SETS_LUMA 4 ///< number of context model sets for luminance +#define NUM_CTX_SETS_CHROMA 2 ///< number of context model sets for combined chrominance + +#define FIRST_CTX_SET_LUMA 0 ///< index of first luminance context set + +//------------------ + +#define NUM_ONE_FLAG_CTX_LUMA (NUM_ONE_FLAG_CTX_PER_SET * NUM_CTX_SETS_LUMA) ///< number of context models for greater than 1 flag of luma +#define NUM_ONE_FLAG_CTX_CHROMA (NUM_ONE_FLAG_CTX_PER_SET * NUM_CTX_SETS_CHROMA) ///< number of context models for greater than 1 flag of chroma + +#define NUM_ABS_FLAG_CTX_LUMA (NUM_ABS_FLAG_CTX_PER_SET * NUM_CTX_SETS_LUMA) ///< number of context models for greater than 2 flag of luma +#define NUM_ABS_FLAG_CTX_CHROMA (NUM_ABS_FLAG_CTX_PER_SET * NUM_CTX_SETS_CHROMA) ///< number of context models for greater than 2 flag of chroma + +#define NUM_ONE_FLAG_CTX (NUM_ONE_FLAG_CTX_LUMA + NUM_ONE_FLAG_CTX_CHROMA) ///< number of context models for greater than 1 flag +#define NUM_ABS_FLAG_CTX (NUM_ABS_FLAG_CTX_LUMA + NUM_ABS_FLAG_CTX_CHROMA) ///< number of context models for greater than 2 flag + +#define FIRST_CTX_SET_CHROMA (FIRST_CTX_SET_LUMA + NUM_CTX_SETS_LUMA) ///< index of first chrominance context set + +//-------------------------------------------------------------------------------------------------- + +// context size definitions for CBF + +#define NUM_QT_CBF_CTX_SETS 2 + +#define NUM_QT_CBF_CTX_PER_SET 5 ///< number of context models for QT CBF + +#define FIRST_CBF_CTX_LUMA 0 ///< index of first luminance CBF context + +#define FIRST_CBF_CTX_CHROMA (FIRST_CBF_CTX_LUMA + NUM_QT_CBF_CTX_PER_SET) ///< index of first chrominance CBF context + + +//-------------------------------------------------------------------------------------------------- + +#define NUM_MVP_IDX_CTX 1 ///< number of context models for MVP index + +#define NUM_SAO_MERGE_FLAG_CTX 1 ///< number of context models for SAO merge flags +#define NUM_SAO_TYPE_IDX_CTX 1 ///< number of context models for SAO type index + +#define NUM_TRANSFORMSKIP_FLAG_CTX 1 ///< number of context models for transform skipping + +#define NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX 1 + +#define NUM_CROSS_COMPONENT_PREDICTION_CTX 10 + +#define CNU 154 ///< dummy initialization value for unused context models 'Context model Not Used' + + +// ==================================================================================================================== +// Tables +// ==================================================================================================================== + +// initial probability for cu_transquant_bypass flag +static const UChar +INIT_CU_TRANSQUANT_BYPASS_FLAG[NUMBER_OF_SLICE_TYPES][NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX] = +{ + { 154 }, + { 154 }, + { 154 }, +}; + +// initial probability for split flag +static const UChar +INIT_SPLIT_FLAG[NUMBER_OF_SLICE_TYPES][NUM_SPLIT_FLAG_CTX] = +{ + { 107, 139, 126, }, + { 107, 139, 126, }, + { 139, 141, 157, }, +}; + +static const UChar +INIT_SKIP_FLAG[NUMBER_OF_SLICE_TYPES][NUM_SKIP_FLAG_CTX] = +{ + { 197, 185, 201, }, + { 197, 185, 201, }, + { CNU, CNU, CNU, }, +}; + +static const UChar +INIT_MERGE_FLAG_EXT[NUMBER_OF_SLICE_TYPES][NUM_MERGE_FLAG_EXT_CTX] = +{ + { 154, }, + { 110, }, + { CNU, }, +}; + +static const UChar +INIT_MERGE_IDX_EXT[NUMBER_OF_SLICE_TYPES][NUM_MERGE_IDX_EXT_CTX] = +{ + { 137, }, + { 122, }, + { CNU, }, +}; + +static const UChar +INIT_PART_SIZE[NUMBER_OF_SLICE_TYPES][NUM_PART_SIZE_CTX] = +{ + { 154, 139, 154, 154 }, + { 154, 139, 154, 154 }, + { 184, CNU, CNU, CNU }, +}; + +static const UChar +INIT_PRED_MODE[NUMBER_OF_SLICE_TYPES][NUM_PRED_MODE_CTX] = +{ + { 134, }, + { 149, }, + { CNU, }, +}; + +static const UChar +INIT_INTRA_PRED_MODE[NUMBER_OF_SLICE_TYPES][NUM_ADI_CTX] = +{ + { 183, }, + { 154, }, + { 184, }, +}; + +static const UChar +INIT_CHROMA_PRED_MODE[NUMBER_OF_SLICE_TYPES][NUM_CHROMA_PRED_CTX] = +{ + { 152, 139, }, + { 152, 139, }, + { 63, 139, }, +}; + +static const UChar +INIT_INTER_DIR[NUMBER_OF_SLICE_TYPES][NUM_INTER_DIR_CTX] = +{ + { 95, 79, 63, 31, 31, }, + { 95, 79, 63, 31, 31, }, + { CNU, CNU, CNU, CNU, CNU, }, +}; + +static const UChar +INIT_MVD[NUMBER_OF_SLICE_TYPES][NUM_MV_RES_CTX] = +{ + { 169, 198, }, + { 140, 198, }, + { CNU, CNU, }, +}; + +static const UChar +INIT_REF_PIC[NUMBER_OF_SLICE_TYPES][NUM_REF_NO_CTX] = +{ + { 153, 153 }, + { 153, 153 }, + { CNU, CNU }, +}; + +static const UChar +INIT_DQP[NUMBER_OF_SLICE_TYPES][NUM_DELTA_QP_CTX] = +{ + { 154, 154, 154, }, + { 154, 154, 154, }, + { 154, 154, 154, }, +}; + +static const UChar +INIT_CHROMA_QP_ADJ_FLAG[NUMBER_OF_SLICE_TYPES][NUM_CHROMA_QP_ADJ_FLAG_CTX] = +{ + { 154, }, + { 154, }, + { 154, }, +}; + +static const UChar +INIT_CHROMA_QP_ADJ_IDC[NUMBER_OF_SLICE_TYPES][NUM_CHROMA_QP_ADJ_IDC_CTX] = +{ + { 154, }, + { 154, }, + { 154, }, +}; + +//-------------------------------------------------------------------------------------------------- + +//Initialisation for CBF + +// |---------Luminance---------| +#define BSLICE_LUMA_CBF_CONTEXT 153, 111, CNU, CNU, CNU +#define PSLICE_LUMA_CBF_CONTEXT 153, 111, CNU, CNU, CNU +#define ISLICE_LUMA_CBF_CONTEXT 111, 141, CNU, CNU, CNU +// |--------Chrominance--------| +#define BSLICE_CHROMA_CBF_CONTEXT 149, 92, 167, 154, 154 +#define PSLICE_CHROMA_CBF_CONTEXT 149, 107, 167, 154, 154 +#define ISLICE_CHROMA_CBF_CONTEXT 94, 138, 182, 154, 154 + + +static const UChar +INIT_QT_CBF[NUMBER_OF_SLICE_TYPES][NUM_QT_CBF_CTX_SETS * NUM_QT_CBF_CTX_PER_SET] = +{ + { BSLICE_LUMA_CBF_CONTEXT, BSLICE_CHROMA_CBF_CONTEXT }, + { PSLICE_LUMA_CBF_CONTEXT, PSLICE_CHROMA_CBF_CONTEXT }, + { ISLICE_LUMA_CBF_CONTEXT, ISLICE_CHROMA_CBF_CONTEXT }, +}; + + +//-------------------------------------------------------------------------------------------------- + +static const UChar +INIT_QT_ROOT_CBF[NUMBER_OF_SLICE_TYPES][NUM_QT_ROOT_CBF_CTX] = +{ + { 79, }, + { 79, }, + { CNU, }, +}; + + +//-------------------------------------------------------------------------------------------------- + +//Initialisation for last-significant-position + +// |------------------------------Luminance----------------------------------| +#define BSLICE_LUMA_LAST_POSITION_CONTEXT 125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111, 79 +#define PSLICE_LUMA_LAST_POSITION_CONTEXT 125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95, 94 +#define ISLICE_LUMA_LAST_POSITION_CONTEXT 110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111, 79 +// |------------------------------Chrominance--------------------------------| +#define BSLICE_CHROMA_LAST_POSITION_CONTEXT 108, 123, 93, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU +#define PSLICE_CHROMA_LAST_POSITION_CONTEXT 108, 123, 108, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU +#define ISLICE_CHROMA_LAST_POSITION_CONTEXT 108, 123, 63, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU + + +static const UChar +INIT_LAST[NUMBER_OF_SLICE_TYPES][NUM_CTX_LAST_FLAG_SETS * NUM_CTX_LAST_FLAG_XY] = +{ + { BSLICE_LUMA_LAST_POSITION_CONTEXT, BSLICE_CHROMA_LAST_POSITION_CONTEXT }, + { PSLICE_LUMA_LAST_POSITION_CONTEXT, PSLICE_CHROMA_LAST_POSITION_CONTEXT }, + { ISLICE_LUMA_LAST_POSITION_CONTEXT, ISLICE_CHROMA_LAST_POSITION_CONTEXT }, +}; + + +//-------------------------------------------------------------------------------------------------- + +static const UChar +INIT_SIG_CG_FLAG[NUMBER_OF_SLICE_TYPES][2 * NUM_SIG_CG_FLAG_CTX] = +{ + { 121, 140, + 61, 154, + }, + { 121, 140, + 61, 154, + }, + { 91, 171, + 134, 141, + }, +}; + + +//-------------------------------------------------------------------------------------------------- + +//Initialisation for significance map + +// |-DC-| |-----------------4x4------------------| |------8x8 Diagonal Scan------| |----8x8 Non-Diagonal Scan----| |-NxN First group-| |-NxN Other group-| |-Single context-| +// | | | | |-First Group-| |-Other Group-| |-First Group-| |-Other Group-| | | | | | | +#define BSLICE_LUMA_SIGNIFICANCE_CONTEXT 170, 154, 139, 153, 139, 123, 123, 63, 124, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 140 +#define PSLICE_LUMA_SIGNIFICANCE_CONTEXT 155, 154, 139, 153, 139, 123, 123, 63, 153, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 140 +#define ISLICE_LUMA_SIGNIFICANCE_CONTEXT 111, 111, 125, 110, 110, 94, 124, 108, 124, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 141 + +// |-DC-| |-----------------4x4------------------| |-8x8 Any group-| |-NxN Any group-| |-Single context-| +#define BSLICE_CHROMA_SIGNIFICANCE_CONTEXT 170, 153, 138, 138, 122, 121, 122, 121, 167, 151, 183, 140, 151, 183, 140, 140 +#define PSLICE_CHROMA_SIGNIFICANCE_CONTEXT 170, 153, 123, 123, 107, 121, 107, 121, 167, 151, 183, 140, 151, 183, 140, 140 +#define ISLICE_CHROMA_SIGNIFICANCE_CONTEXT 140, 139, 182, 182, 152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111, 111 + +//------------------------------------------------ + +static const UChar +INIT_SIG_FLAG[NUMBER_OF_SLICE_TYPES][NUM_SIG_FLAG_CTX] = +{ + { BSLICE_LUMA_SIGNIFICANCE_CONTEXT, BSLICE_CHROMA_SIGNIFICANCE_CONTEXT }, + { PSLICE_LUMA_SIGNIFICANCE_CONTEXT, PSLICE_CHROMA_SIGNIFICANCE_CONTEXT }, + { ISLICE_LUMA_SIGNIFICANCE_CONTEXT, ISLICE_CHROMA_SIGNIFICANCE_CONTEXT }, +}; + + +//-------------------------------------------------------------------------------------------------- + +//Initialisation for greater-than-one flags and greater-than-two flags + +// |------Set 0-------| |------Set 1-------| |------Set 2-------| |------Set 3-------| +#define BSLICE_LUMA_ONE_CONTEXT 154, 196, 167, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121, 136, 122 +#define PSLICE_LUMA_ONE_CONTEXT 154, 196, 196, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121, 136, 137 +#define ISLICE_LUMA_ONE_CONTEXT 140, 92, 137, 138, 140, 152, 138, 139, 153, 74, 149, 92, 139, 107, 122, 152 + +#define BSLICE_LUMA_ABS_CONTEXT 107, 167, 91, 107 +#define PSLICE_LUMA_ABS_CONTEXT 107, 167, 91, 122 +#define ISLICE_LUMA_ABS_CONTEXT 138, 153, 136, 167 + +// |------Set 4-------| |------Set 5-------| +#define BSLICE_CHROMA_ONE_CONTEXT 169, 208, 166, 167, 154, 152, 167, 182 +#define PSLICE_CHROMA_ONE_CONTEXT 169, 194, 166, 167, 154, 167, 137, 182 +#define ISLICE_CHROMA_ONE_CONTEXT 140, 179, 166, 182, 140, 227, 122, 197 + +#define BSLICE_CHROMA_ABS_CONTEXT 107, 167 +#define PSLICE_CHROMA_ABS_CONTEXT 107, 167 +#define ISLICE_CHROMA_ABS_CONTEXT 152, 152 + + +//------------------------------------------------ + +static const UChar +INIT_ONE_FLAG[NUMBER_OF_SLICE_TYPES][NUM_ONE_FLAG_CTX] = +{ + { BSLICE_LUMA_ONE_CONTEXT, BSLICE_CHROMA_ONE_CONTEXT }, + { PSLICE_LUMA_ONE_CONTEXT, PSLICE_CHROMA_ONE_CONTEXT }, + { ISLICE_LUMA_ONE_CONTEXT, ISLICE_CHROMA_ONE_CONTEXT }, +}; + +static const UChar +INIT_ABS_FLAG[NUMBER_OF_SLICE_TYPES][NUM_ABS_FLAG_CTX] = +{ + { BSLICE_LUMA_ABS_CONTEXT, BSLICE_CHROMA_ABS_CONTEXT }, + { PSLICE_LUMA_ABS_CONTEXT, PSLICE_CHROMA_ABS_CONTEXT }, + { ISLICE_LUMA_ABS_CONTEXT, ISLICE_CHROMA_ABS_CONTEXT }, +}; + + +//-------------------------------------------------------------------------------------------------- + +static const UChar +INIT_MVP_IDX[NUMBER_OF_SLICE_TYPES][NUM_MVP_IDX_CTX] = +{ + { 168, }, + { 168, }, + { CNU, }, +}; + +static const UChar +INIT_SAO_MERGE_FLAG[NUMBER_OF_SLICE_TYPES][NUM_SAO_MERGE_FLAG_CTX] = +{ + { 153, }, + { 153, }, + { 153, }, +}; + +static const UChar +INIT_SAO_TYPE_IDX[NUMBER_OF_SLICE_TYPES][NUM_SAO_TYPE_IDX_CTX] = +{ + { 160, }, + { 185, }, + { 200, }, +}; + +static const UChar +INIT_TRANS_SUBDIV_FLAG[NUMBER_OF_SLICE_TYPES][NUM_TRANS_SUBDIV_FLAG_CTX] = +{ + { 224, 167, 122, }, + { 124, 138, 94, }, + { 153, 138, 138, }, +}; + +static const UChar +INIT_TRANSFORMSKIP_FLAG[NUMBER_OF_SLICE_TYPES][2*NUM_TRANSFORMSKIP_FLAG_CTX] = +{ + { 139, 139}, + { 139, 139}, + { 139, 139}, +}; + +static const UChar +INIT_EXPLICIT_RDPCM_FLAG[NUMBER_OF_SLICE_TYPES][2*NUM_EXPLICIT_RDPCM_FLAG_CTX] = +{ + {139, 139}, + {139, 139}, + {CNU, CNU} +}; + +static const UChar +INIT_EXPLICIT_RDPCM_DIR[NUMBER_OF_SLICE_TYPES][2*NUM_EXPLICIT_RDPCM_DIR_CTX] = +{ + {139, 139}, + {139, 139}, + {CNU, CNU} +}; + +static const UChar +INIT_CROSS_COMPONENT_PREDICTION[NUMBER_OF_SLICE_TYPES][NUM_CROSS_COMPONENT_PREDICTION_CTX] = +{ + { 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 }, + { 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 }, + { 154, 154, 154, 154, 154, 154, 154, 154, 154, 154 }, +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/Debug.cpp b/jctvc/TLibCommon/Debug.cpp new file mode 100644 index 0000000..cefb8c2 --- /dev/null +++ b/jctvc/TLibCommon/Debug.cpp @@ -0,0 +1,449 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file Debug.cpp + \brief Defines types and objects for environment-variable-based debugging and feature control +*/ + +#include "Debug.h" +#include +#include +#include "TComDataCU.h" +#include "TComPic.h" +#include "TComYuv.h" + +static const UInt settingNameWidth = 66; +static const UInt settingHelpWidth = 84; +static const UInt settingValueWidth = 3; + +#ifdef DEBUG_STRING +// these strings are used to reorder the debug output so that the encoder and decoder match. +const Char *debug_reorder_data_inter_token[MAX_NUM_COMPONENT+1] + = {"Start of channel 0 inter debug\n", "Start of channel 1 inter debug\n", "Start of channel 2 inter debug\n", "End of inter residual debug\n"} ; +const Char *partSizeToString[NUMBER_OF_PART_SIZES]={"2Nx2N(0)", "2NxN(1)", "Nx2N(2)", "NxN(3)", "2Nx(N/2+3N/2)(4)", "2Nx(3N/2+N/2)(5)", "(N/2+3N/2)x2N(6)", "(3N/2+N/2)x2N(7)"}; +#endif + +// --------------------------------------------------------------------------------------------------------------------- // + +//EnvVar definition + +std::list > &EnvVar::getEnvVarList() +{ + static std::list > varInfoList; + return varInfoList; +} + +std::list &EnvVar::getEnvVarInUse() +{ + static std::list varInUseList; + return varInUseList; +} + +static inline Void printPair(const std::pair &p) +{ + if (p.second=="") + { + std::cout << "\n" << std::setw(settingNameWidth) << p.first << "\n" << std::endl; + } + else + { + std::cout << std::setw(settingNameWidth) << p.first << ": " << p.second << "\n" << std::endl; + } +} + +static inline Void printVal(const EnvVar* env) +{ + std::cout << std::setw(settingNameWidth) << env->getName() << " = " << std::setw(settingValueWidth) << env->getInt() << " (string = " << std::setw(15) << env->getString() << ")" << std::endl; +} + +//static inline Bool sameEnvName( const std::pair &a, +// const std::pair &b ) +//{ +// // only check env name +// return (a.first==b.first); +//} + +Void EnvVar::printEnvVar() +{ +// getEnvVarList().unique(sameEnvName); + if (getEnvVarList().size()!=0) + { + std::cout << "--- Environment variables:\n" << std::endl; + for_each(getEnvVarList().begin(), getEnvVarList().end(), printPair); + } + std::cout << std::endl; +} + +Void EnvVar::printEnvVarInUse() +{ + if (getEnvVarInUse().size()!=0) + { + std::cout << "RExt Environment variables set as follows: \n" << std::endl; + for_each(getEnvVarInUse().begin(), getEnvVarInUse().end(), printVal); + } + std::cout << std::endl; +} + +EnvVar::EnvVar(const std::string &sName, const std::string &sDefault, const std::string &sHelp) : + m_sName(sName), + m_sHelp(sHelp), + m_sVal(), + m_dVal(0), + m_iVal(0), + m_bSet(false) +{ + if (getenv(m_sName.c_str())) + { + m_sVal = getenv(m_sName.c_str()); + m_bSet = true; + getEnvVarInUse().push_back(this); + } + else m_sVal = sDefault; + + m_dVal = strtod(m_sVal.c_str(), 0); + m_iVal = Int(m_dVal); + + getEnvVarList().push_back( std::pair(m_sName, indentNewLines(lineWrap(splitOnSettings(m_sHelp), settingHelpWidth), (settingNameWidth + 4))) ); +} + + +// --------------------------------------------------------------------------------------------------------------------- // + +// Debug environment variables: + +EnvVar Debug("-- Debugging","",""); + +EnvVar DebugOptionList::DebugSBAC ("DEBUG_SBAC", "0", "Output debug data from SBAC entropy coder (coefficient data etc.)" ); +EnvVar DebugOptionList::DebugRQT ("DEBUG_RQT", "0", "Output RQT debug data from entropy coder" ); +EnvVar DebugOptionList::DebugPred ("DEBUG_PRED", "0", "Output prediction debug" ); +EnvVar DebugOptionList::ForceLumaMode ("FORCE_LUMA_MODE", "0", "Force a particular intra direction for Luma (0-34)" ); +EnvVar DebugOptionList::ForceChromaMode ("FORCE_CHROMA_MODE", "0", "Force a particular intra direction for chroma (0-5)" ); + +#ifdef DEBUG_STRING +EnvVar DebugOptionList::DebugString_Structure ("DEBUG_STRUCTURE", "0", "Produce output on chosen structure bit0=intra, bit1=inter"); +EnvVar DebugOptionList::DebugString_Pred ("DEBUG_PRED", "0", "Produce output on prediction data. bit0=intra, bit1=inter"); +EnvVar DebugOptionList::DebugString_Resi ("DEBUG_RESI", "0", "Produce output on residual data. bit0=intra, bit1=inter"); +EnvVar DebugOptionList::DebugString_Reco ("DEBUG_RECO", "0", "Produce output on reconstructed data. bit0=intra, bit1=inter"); +EnvVar DebugOptionList::DebugString_InvTran ("DEBUG_INV_QT", "0", "Produce output on inverse-quantiser and transform stages. bit0=intra, bit1=inter"); +#endif + +// --------------------------------------------------------------------------------------------------------------------- // + +//macro value printing function + +Void printMacroSettings() +{ + std::cout << "Non-environment-variable-controlled macros set as follows: \n" << std::endl; + + //------------------------------------------------ + + //setting macros + + PRINT_CONSTANT(RExt__DECODER_DEBUG_BIT_STATISTICS, settingNameWidth, settingValueWidth); + PRINT_CONSTANT(RExt__HIGH_BIT_DEPTH_SUPPORT, settingNameWidth, settingValueWidth); + PRINT_CONSTANT(RExt__HIGH_PRECISION_FORWARD_TRANSFORM, settingNameWidth, settingValueWidth); + + PRINT_CONSTANT(O0043_BEST_EFFORT_DECODING, settingNameWidth, settingValueWidth); + + PRINT_CONSTANT(RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL, settingNameWidth, settingValueWidth); + + //------------------------------------------------ + + std::cout << std::endl; +} + + +// --------------------------------------------------------------------------------------------------------------------- // + +//Debugging + +UInt g_debugCounter = 0; +Bool g_printDebug = false; +Void* g_debugAddr = NULL; + +#ifdef DEBUG_ENCODER_SEARCH_BINS +const UInt debugEncoderSearchBinTargetLine = 0; +const UInt debugEncoderSearchBinWindow = 1000000; +#endif + +#ifdef DEBUG_CABAC_BINS +const UInt debugCabacBinTargetLine = 0; +const UInt debugCabacBinWindow = 1000000; +#endif + +Void printSBACCoeffData( const UInt lastX, + const UInt lastY, + const UInt width, + const UInt height, + const UInt chan, + const UInt absPart, + const UInt scanIdx, + const TCoeff *const pCoeff, + const Bool finalEncode + ) +{ + if (DebugOptionList::DebugSBAC.getInt()!=0 && finalEncode) + { + std::cout << "Size: " << width << "x" << height << ", Last X/Y: (" << lastX << ", " << lastY << "), absPartIdx: " << absPart << ", scanIdx: " << scanIdx << ", chan: " << chan << std::endl; + for (Int i=0; igetWidth(0)/4; + const UInt numValidComp=pcCU->getPic()->getNumberValidComponents(); + for (UInt ch=0; chgetCbf(compID)[g_auiRasterToZscan[y*CUSizeInParts + x]]); + } + } + } +} + +UInt getDecimalWidth(const Double value) +{ + return (value == 0) ? 1 : (UInt(floor(log10(fabs(value)))) + ((value < 0) ? 2 : 1)); + //for the minus sign +} + +UInt getZScanIndex(const UInt x, const UInt y) +{ + UInt remainingX = x; + UInt remainingY = y; + UInt offset = 0; + UInt result = 0; + + while ((remainingX != 0) || (remainingY != 0)) + { + result |= ((remainingX & 0x1) << offset) | ((remainingY & 0x1) << (offset + 1)); + + remainingX >>= 1; + remainingY >>= 1; + offset += 2; + } + + return result; +} + + +// --------------------------------------------------------------------------------------------------------------------- // + +//String manipulation functions for aligning and wrapping printed text + + +std::string splitOnSettings(const std::string &input) +{ + std::string result = input; + + std::string::size_type searchFromPosition = 0; + + while (searchFromPosition < result.length()) + { + //find the " = " that is used to define each setting + std::string::size_type equalsPosition = result.find(" = ", searchFromPosition); + + if (equalsPosition == std::string::npos) break; + + //then find the end of the numeric characters + std::string::size_type splitPosition = result.find_last_of("1234567890", equalsPosition); + + //then find the last space before the first numeric character... + if (splitPosition != std::string::npos) splitPosition = result.find_last_of(' ', splitPosition); + + //...and replace it with a new line + if (splitPosition != std::string::npos) result.replace(splitPosition, 1, 1, '\n'); + + //start the next search from the end of the " = " string + searchFromPosition = (equalsPosition + 3); + } + + return result; +} + + +std::string lineWrap(const std::string &input, const UInt maximumLineLength) +{ + if (maximumLineLength == 0) return input; + std::string result = input; + + std::string::size_type lineStartPosition = result.find_first_not_of(' '); //don't wrap any leading spaces in the string + + while (lineStartPosition != std::string::npos) + { + //------------------------------------------------ + + const std::string::size_type searchFromPosition = lineStartPosition + maximumLineLength; + + if (searchFromPosition >= result.length()) break; + + //------------------------------------------------ + + //first check to see if there is another new line character before the maximum line length + //we can't use find for this unfortunately because it doesn't take both a beginning and an end for its search range + std::string::size_type nextLineStartPosition = std::string::npos; + for (std::string::size_type currentPosition = lineStartPosition; currentPosition <= searchFromPosition; currentPosition++) + { + if (result[currentPosition] == '\n') { nextLineStartPosition = currentPosition + 1; break; } + } + + //------------------------------------------------ + + //if there ia another new line character before the maximum line length, we need to start this loop again from that position + if (nextLineStartPosition != std::string::npos) lineStartPosition = nextLineStartPosition; + else + { + std::string::size_type spacePosition = std::string::npos; + + //search backwards for the last space character (must use signed Int because lineStartPosition can be 0) + for (Int currentPosition = Int(searchFromPosition); currentPosition >= Int(lineStartPosition); currentPosition--) + { + if (result[currentPosition] == ' ') { spacePosition = currentPosition; break; } + } + + //if we didn't find a space searching backwards, we must hyphenate + if (spacePosition == std::string::npos) + { + result.insert(searchFromPosition, "-\n"); + lineStartPosition = searchFromPosition + 2; //make sure the next search ignores the hyphen + } + else //if we found a space to split on, replace it with a new line character + { + result.replace(spacePosition, 1, 1, '\n'); + lineStartPosition = spacePosition + 1; + } + } + + //------------------------------------------------ + } + + return result; +} + + +std::string indentNewLines(const std::string &input, const UInt indentBy) +{ + std::string result = input; + + const std::string indentString(indentBy, ' '); + std::string::size_type offset = 0; + + while ((offset = result.find('\n', offset)) != std::string::npos) + { + if ((++offset) >= result.length()) break; //increment offset so we don't find the same \n again and do no indentation at the end + result.insert(offset, indentString); + } + + return result; +} + + +// --------------------------------------------------------------------------------------------------------------------- // + + +Void printBlockToStream( std::ostream &ss, const Char *pLinePrefix, TComYuv &src, const UInt numSubBlocksAcross, const UInt numSubBlocksUp, const UInt defWidth ) +{ + const UInt numValidComp=src.getNumberValidComponents(); + + for (UInt ch=0; ch +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_STRING +extern const Char *debug_reorder_data_inter_token[MAX_NUM_COMPONENT+1]; +extern const Char *partSizeToString[NUMBER_OF_PART_SIZES]; +#endif + +// ---------------------------------------------------------------------------------------------- // + +//constant print-out macro + +#define PRINT_CONSTANT(NAME, NAME_WIDTH, VALUE_WIDTH) std::cout << std::setw(NAME_WIDTH) << #NAME << " = " << std::setw(VALUE_WIDTH) << NAME << std::endl; + +// ---------------------------------------------------------------------------------------------- // + +// ---- Environment variables for test/debug ---- // + +class EnvVar +{ +private: + std::string m_sName; + std::string m_sHelp; + std::string m_sVal; + Double m_dVal; + Int m_iVal; + Bool m_bSet; + +public: + + static std::list< std::pair > &getEnvVarList(); + static std::list &getEnvVarInUse(); + static Void printEnvVar(); + static Void printEnvVarInUse(); + + EnvVar(const std::string &sName, const std::string &sDefault, const std::string &sHelp); + + Double getDouble() const { return m_dVal; } + Int getInt() const { return m_iVal; } + const std::string &getString() const { return m_sVal; } + Bool isSet() const { return m_bSet; } + Bool isTrue() const { return m_iVal!=0; } + const std::string &getName() const { return m_sName; } + +}; + + +// ---------------------------------------------------------------------------------------------- // + +// ---- Control switches for debugging and feature control ---- // + +namespace DebugOptionList +{ + extern EnvVar DebugSBAC; + extern EnvVar DebugRQT; + extern EnvVar DebugPred; + extern EnvVar ForceLumaMode; + extern EnvVar ForceChromaMode; + +#ifdef DEBUG_STRING + extern EnvVar DebugString_Structure; + extern EnvVar DebugString_Pred; + extern EnvVar DebugString_Resi; + extern EnvVar DebugString_Reco; + extern EnvVar DebugString_InvTran; +#endif +} + +// ---------------------------------------------------------------------------------------------- // + +Void printMacroSettings(); + +// ---------------------------------------------------------------------------------------------- // + +//Debugging + +extern Bool g_bFinalEncode; +extern UInt g_debugCounter; +extern Bool g_printDebug; +extern Void* g_debugAddr; + +#ifdef DEBUG_ENCODER_SEARCH_BINS +extern const UInt debugEncoderSearchBinTargetLine; +extern const UInt debugEncoderSearchBinWindow; +#endif + +#ifdef DEBUG_CABAC_BINS +extern const UInt debugCabacBinTargetLine; +extern const UInt debugCabacBinWindow; +#endif + + +Void printSBACCoeffData( const UInt lastX, + const UInt lastY, + const UInt width, + const UInt height, + const UInt chan, + const UInt absPart, + const UInt scanIdx, + const TCoeff *const pCoeff, + const Bool finalEncode=true + ); + + +Void printCbfArray( class TComDataCU* pcCU ); + +UInt getDecimalWidth(const Double value); +UInt getZScanIndex(const UInt x, const UInt y); + +//template specialisation for Char types to get it to render as a number +template inline Void writeValueToStream (const ValueType &value, std::ostream &stream, const UInt outputWidth) { stream << std::setw(outputWidth) << value; } +template <> inline Void writeValueToStream(const Char &value, std::ostream &stream, const UInt outputWidth) { stream << std::setw(outputWidth) << Int(value); } +template <> inline Void writeValueToStream(const UChar &value, std::ostream &stream, const UInt outputWidth) { stream << std::setw(outputWidth) << UInt(value); } + +template +Void printBlock(const ValueType *const source, + const UInt width, + const UInt height, + const UInt stride, + const UInt outputValueWidth = 0, //if set to 0, the maximum output width will be calculated and used + const Bool onlyPrintEdges = false, //print only the top row and left column for printing prediction reference samples + const Bool printInZScan = false, //output values in Z-scan format (useful for values addressed by AbsPartIdxes) + const Int shiftLeftBy = 0, //set a negative value to right-shift instead + const Bool printAverage = false, //also print the average of the values in the block + std::ostream & stream = std::cout) +{ + //find the maximum output width + UInt outputWidth = outputValueWidth; + + if (outputWidth == 0) + { + ValueType minimumValue = leftShift(source[0], shiftLeftBy); + ValueType maximumValue = minimumValue; + + for (UInt y = 0; y < height; y++) + for (UInt x = 0; x < width; x++) + { + ValueType value = 0; + + if (!onlyPrintEdges || (x == 0) || (y == 0)) + { + value = leftShift(source[printInZScan ? getZScanIndex(x, y) : ((y * stride) + x)], shiftLeftBy); + } + + if (value < minimumValue) minimumValue = value; + else if (value > maximumValue) maximumValue = value; + } + + outputWidth = std::max(getDecimalWidth(Double(minimumValue)), getDecimalWidth(Double(maximumValue))) + 1; //+1 so the numbers don't run into each other + } + + //------------------ + //print out the block + + ValueType valueSum = 0; + + for (UInt y = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++) + { + ValueType value = 0; + + if (!onlyPrintEdges || (x == 0) || (y == 0)) + { + value = leftShift(source[printInZScan ? getZScanIndex(x, y) : ((y * stride) + x)], shiftLeftBy); + valueSum += value; + } + + writeValueToStream(value, stream, outputWidth); + } + stream << "\n"; + } + + const Int valueCount = onlyPrintEdges ? Int((width + height) - 1) : Int(width * height); + if (printAverage) stream << "Average: " << (valueSum / valueCount) << "\n"; + stream << "\n"; +} + + +template +Void printBlockToStream( std::ostream &ss, const Char *pLinePrefix, const T * blkSrc, const UInt width, const UInt height, const UInt stride, const UInt subBlockWidth=0, const UInt subBlockHeight=0, const UInt defWidth=3 ) +{ + for (UInt y=0; y +#include +#include "CommonDef.h" + +class TComOutputBitstream; + +/** + * Represents a single NALunit header and the associated RBSPayload + */ +struct NALUnit +{ + NalUnitType m_nalUnitType; ///< nal_unit_type + UInt m_temporalId; ///< temporal_id + UInt m_reservedZero6Bits; ///< reserved_zero_6bits + + /** construct an NALunit structure with given header values. */ + NALUnit( + NalUnitType nalUnitType, + Int temporalId = 0, + Int reservedZero6Bits = 0) + :m_nalUnitType (nalUnitType) + ,m_temporalId (temporalId) + ,m_reservedZero6Bits(reservedZero6Bits) + {} + + /** default constructor - no initialization; must be perfomed by user */ + NALUnit() {} + + /** returns true if the NALunit is a slice NALunit */ + Bool isSlice() + { + return m_nalUnitType == NAL_UNIT_CODED_SLICE_TRAIL_R + || m_nalUnitType == NAL_UNIT_CODED_SLICE_TRAIL_N + || m_nalUnitType == NAL_UNIT_CODED_SLICE_TSA_R + || m_nalUnitType == NAL_UNIT_CODED_SLICE_TSA_N + || m_nalUnitType == NAL_UNIT_CODED_SLICE_STSA_R + || m_nalUnitType == NAL_UNIT_CODED_SLICE_STSA_N + || m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_LP + || m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_N_LP + || m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL + || m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_N_LP + || m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA + || m_nalUnitType == NAL_UNIT_CODED_SLICE_RADL_N + || m_nalUnitType == NAL_UNIT_CODED_SLICE_RADL_R + || m_nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N + || m_nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R; + } + Bool isSei() + { + return m_nalUnitType == NAL_UNIT_PREFIX_SEI + || m_nalUnitType == NAL_UNIT_SUFFIX_SEI; + } + + Bool isVcl() + { + return ( (UInt)m_nalUnitType < 32 ); + } +}; + +struct OutputNALUnit; + +/** + * A single NALunit, with complete payload in EBSP format. + */ +struct NALUnitEBSP : public NALUnit +{ + std::ostringstream m_nalUnitData; + + /** + * convert the OutputNALUnit #nalu# into EBSP format by writing out + * the NALUnit header, then the rbsp_bytes including any + * emulation_prevention_three_byte symbols. + */ + NALUnitEBSP(OutputNALUnit& nalu); +}; +//! \} +//! \} + +#endif diff --git a/jctvc/TLibCommon/SEI.cpp b/jctvc/TLibCommon/SEI.cpp new file mode 100644 index 0000000..0e15948 --- /dev/null +++ b/jctvc/TLibCommon/SEI.cpp @@ -0,0 +1,126 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file SEI.cpp + \brief helper functions for SEI handling +*/ + +#include "CommonDef.h" +#include "SEI.h" + +//Table D-7 Meaning of camera iso sensitivity indicator and exposure index rating indicator +Int Table_exp_indicator[32] = {0, 10, 12, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 8000, -1}; + +SEIMessages getSeisByType(SEIMessages &seiList, SEI::PayloadType seiType) +{ + SEIMessages result; + + for (SEIMessages::iterator it=seiList.begin(); it!=seiList.end(); it++) + { + if ((*it)->payloadType() == seiType) + { + result.push_back(*it); + } + } + return result; +} + +SEIMessages extractSeisByType(SEIMessages &seiList, SEI::PayloadType seiType) +{ + SEIMessages result; + + SEIMessages::iterator it=seiList.begin(); + while ( it!=seiList.end() ) + { + if ((*it)->payloadType() == seiType) + { + result.push_back(*it); + it = seiList.erase(it); + } + else + { + it++; + } + } + return result; +} + + +Void deleteSEIs (SEIMessages &seiList) +{ + for (SEIMessages::iterator it=seiList.begin(); it!=seiList.end(); it++) + { + delete (*it); + } + seiList.clear(); +} + + +// Static member +const Char *SEI::getSEIMessageString(SEI::PayloadType payloadType) +{ + switch (payloadType) + { + case SEI::BUFFERING_PERIOD: return "Buffering period"; + case SEI::PICTURE_TIMING: return "Picture timing"; + case SEI::PAN_SCAN_RECT: return "Pan-scan rectangle"; // not currently decoded + case SEI::FILLER_PAYLOAD: return "Filler payload"; // not currently decoded + case SEI::USER_DATA_REGISTERED_ITU_T_T35: return "User data registered"; // not currently decoded + case SEI::USER_DATA_UNREGISTERED: return "User data unregistered"; + case SEI::RECOVERY_POINT: return "Recovery point"; + case SEI::SCENE_INFO: return "Scene information"; // not currently decoded + case SEI::FULL_FRAME_SNAPSHOT: return "Picture snapshot"; // not currently decoded + case SEI::PROGRESSIVE_REFINEMENT_SEGMENT_START: return "Progressive refinement segment start"; // not currently decoded + case SEI::PROGRESSIVE_REFINEMENT_SEGMENT_END: return "Progressive refinement segment end"; // not currently decoded + case SEI::FILM_GRAIN_CHARACTERISTICS: return "Film grain characteristics"; // not currently decoded + case SEI::POST_FILTER_HINT: return "Post filter hint"; // not currently decoded + case SEI::TONE_MAPPING_INFO: return "Tone mapping information"; + case SEI::KNEE_FUNCTION_INFO: return "Knee function information"; + case SEI::FRAME_PACKING: return "Frame packing arrangement"; + case SEI::DISPLAY_ORIENTATION: return "Display orientation"; + case SEI::SOP_DESCRIPTION: return "Structure of pictures information"; + case SEI::ACTIVE_PARAMETER_SETS: return "Active parameter sets"; + case SEI::DECODING_UNIT_INFO: return "Decoding unit information"; + case SEI::TEMPORAL_LEVEL0_INDEX: return "Temporal sub-layer zero index"; + case SEI::DECODED_PICTURE_HASH: return "Decoded picture hash"; + case SEI::SCALABLE_NESTING: return "Scalable nesting"; + case SEI::REGION_REFRESH_INFO: return "Region refresh information"; + case SEI::NO_DISPLAY: return "No display"; + case SEI::TIME_CODE: return "Time code"; + case SEI::MASTERING_DISPLAY_COLOUR_VOLUME: return "Mastering display colour volume"; + case SEI::SEGM_RECT_FRAME_PACKING: return "Segmented rectangular frame packing arrangement"; + case SEI::TEMP_MOTION_CONSTRAINED_TILE_SETS: return "Temporal motion constrained tile sets"; + case SEI::CHROMA_SAMPLING_FILTER_HINT: return "Chroma sampling filter hint"; + default: return "Unknown"; + } +} diff --git a/jctvc/TLibCommon/SEI.h b/jctvc/TLibCommon/SEI.h new file mode 100644 index 0000000..29093c0 --- /dev/null +++ b/jctvc/TLibCommon/SEI.h @@ -0,0 +1,591 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SEI__ +#define __SEI__ + +#pragma once +#include +#include +#include + +#include "TypeDef.h" +#include "libmd5/MD5.h" + +//! \ingroup TLibCommon +//! \{ +class TComSPS; + +/** + * Abstract class representing an SEI message with lightweight RTTI. + */ +class SEI +{ +public: + enum PayloadType + { + BUFFERING_PERIOD = 0, + PICTURE_TIMING = 1, + PAN_SCAN_RECT = 2, + FILLER_PAYLOAD = 3, + USER_DATA_REGISTERED_ITU_T_T35 = 4, + USER_DATA_UNREGISTERED = 5, + RECOVERY_POINT = 6, + SCENE_INFO = 9, + FULL_FRAME_SNAPSHOT = 15, + PROGRESSIVE_REFINEMENT_SEGMENT_START = 16, + PROGRESSIVE_REFINEMENT_SEGMENT_END = 17, + FILM_GRAIN_CHARACTERISTICS = 19, + POST_FILTER_HINT = 22, + TONE_MAPPING_INFO = 23, + FRAME_PACKING = 45, + DISPLAY_ORIENTATION = 47, + SOP_DESCRIPTION = 128, + ACTIVE_PARAMETER_SETS = 129, + DECODING_UNIT_INFO = 130, + TEMPORAL_LEVEL0_INDEX = 131, + DECODED_PICTURE_HASH = 132, + SCALABLE_NESTING = 133, + REGION_REFRESH_INFO = 134, + NO_DISPLAY = 135, + TIME_CODE = 136, + MASTERING_DISPLAY_COLOUR_VOLUME = 137, + SEGM_RECT_FRAME_PACKING = 138, + TEMP_MOTION_CONSTRAINED_TILE_SETS = 139, + CHROMA_SAMPLING_FILTER_HINT = 140, + KNEE_FUNCTION_INFO = 141 + }; + + SEI() {} + virtual ~SEI() {} + + static const Char *getSEIMessageString(SEI::PayloadType payloadType); + + virtual PayloadType payloadType() const = 0; +}; + +static const UInt ISO_IEC_11578_LEN=16; + +class SEIuserDataUnregistered : public SEI +{ +public: + PayloadType payloadType() const { return USER_DATA_UNREGISTERED; } + + SEIuserDataUnregistered() + : userData(0) + {} + + virtual ~SEIuserDataUnregistered() + { + delete userData; + } + + UChar uuid_iso_iec_11578[ISO_IEC_11578_LEN]; + UInt userDataLength; + UChar *userData; +}; + +class SEIDecodedPictureHash : public SEI +{ +public: + PayloadType payloadType() const { return DECODED_PICTURE_HASH; } + + SEIDecodedPictureHash() {} + virtual ~SEIDecodedPictureHash() {} + + enum Method + { + MD5, + CRC, + CHECKSUM, + RESERVED, + } method; + + TComDigest m_digest; +}; + +class SEIActiveParameterSets : public SEI +{ +public: + PayloadType payloadType() const { return ACTIVE_PARAMETER_SETS; } + + SEIActiveParameterSets() + : activeVPSId (0) + , m_selfContainedCvsFlag (false) + , m_noParameterSetUpdateFlag (false) + , numSpsIdsMinus1 (0) + {} + virtual ~SEIActiveParameterSets() {} + + Int activeVPSId; + Bool m_selfContainedCvsFlag; + Bool m_noParameterSetUpdateFlag; + Int numSpsIdsMinus1; + std::vector activeSeqParameterSetId; +}; + +class SEIBufferingPeriod : public SEI +{ +public: + PayloadType payloadType() const { return BUFFERING_PERIOD; } + + SEIBufferingPeriod() + : m_bpSeqParameterSetId (0) + , m_rapCpbParamsPresentFlag (false) + , m_cpbDelayOffset (0) + , m_dpbDelayOffset (0) + { + ::memset(m_initialCpbRemovalDelay, 0, sizeof(m_initialCpbRemovalDelay)); + ::memset(m_initialCpbRemovalDelayOffset, 0, sizeof(m_initialCpbRemovalDelayOffset)); + ::memset(m_initialAltCpbRemovalDelay, 0, sizeof(m_initialAltCpbRemovalDelay)); + ::memset(m_initialAltCpbRemovalDelayOffset, 0, sizeof(m_initialAltCpbRemovalDelayOffset)); + } + virtual ~SEIBufferingPeriod() {} + + UInt m_bpSeqParameterSetId; + Bool m_rapCpbParamsPresentFlag; + UInt m_cpbDelayOffset; + UInt m_dpbDelayOffset; + UInt m_initialCpbRemovalDelay [MAX_CPB_CNT][2]; + UInt m_initialCpbRemovalDelayOffset [MAX_CPB_CNT][2]; + UInt m_initialAltCpbRemovalDelay [MAX_CPB_CNT][2]; + UInt m_initialAltCpbRemovalDelayOffset[MAX_CPB_CNT][2]; + Bool m_concatenationFlag; + UInt m_auCpbRemovalDelayDelta; +}; +class SEIPictureTiming : public SEI +{ +public: + PayloadType payloadType() const { return PICTURE_TIMING; } + + SEIPictureTiming() + : m_picStruct (0) + , m_sourceScanType (0) + , m_duplicateFlag (false) + , m_picDpbOutputDuDelay (0) + , m_numNalusInDuMinus1 (NULL) + , m_duCpbRemovalDelayMinus1 (NULL) + {} + virtual ~SEIPictureTiming() + { + if( m_numNalusInDuMinus1 != NULL ) + { + delete m_numNalusInDuMinus1; + } + if( m_duCpbRemovalDelayMinus1 != NULL ) + { + delete m_duCpbRemovalDelayMinus1; + } + } + + UInt m_picStruct; + UInt m_sourceScanType; + Bool m_duplicateFlag; + + UInt m_auCpbRemovalDelay; + UInt m_picDpbOutputDelay; + UInt m_picDpbOutputDuDelay; + UInt m_numDecodingUnitsMinus1; + Bool m_duCommonCpbRemovalDelayFlag; + UInt m_duCommonCpbRemovalDelayMinus1; + UInt* m_numNalusInDuMinus1; + UInt* m_duCpbRemovalDelayMinus1; +}; + +class SEIDecodingUnitInfo : public SEI +{ +public: + PayloadType payloadType() const { return DECODING_UNIT_INFO; } + + SEIDecodingUnitInfo() + : m_decodingUnitIdx(0) + , m_duSptCpbRemovalDelay(0) + , m_dpbOutputDuDelayPresentFlag(false) + , m_picSptDpbOutputDuDelay(0) + {} + virtual ~SEIDecodingUnitInfo() {} + Int m_decodingUnitIdx; + Int m_duSptCpbRemovalDelay; + Bool m_dpbOutputDuDelayPresentFlag; + Int m_picSptDpbOutputDuDelay; +}; + +class SEIRecoveryPoint : public SEI +{ +public: + PayloadType payloadType() const { return RECOVERY_POINT; } + + SEIRecoveryPoint() {} + virtual ~SEIRecoveryPoint() {} + + Int m_recoveryPocCnt; + Bool m_exactMatchingFlag; + Bool m_brokenLinkFlag; +}; + +class SEIFramePacking : public SEI +{ +public: + PayloadType payloadType() const { return FRAME_PACKING; } + + SEIFramePacking() {} + virtual ~SEIFramePacking() {} + + Int m_arrangementId; + Bool m_arrangementCancelFlag; + Int m_arrangementType; + Bool m_quincunxSamplingFlag; + Int m_contentInterpretationType; + Bool m_spatialFlippingFlag; + Bool m_frame0FlippedFlag; + Bool m_fieldViewsFlag; + Bool m_currentFrameIsFrame0Flag; + Bool m_frame0SelfContainedFlag; + Bool m_frame1SelfContainedFlag; + Int m_frame0GridPositionX; + Int m_frame0GridPositionY; + Int m_frame1GridPositionX; + Int m_frame1GridPositionY; + Int m_arrangementReservedByte; + Bool m_arrangementPersistenceFlag; + Bool m_upsampledAspectRatio; +}; + +class SEISegmentedRectFramePacking : public SEI +{ +public: + PayloadType payloadType() const { return SEGM_RECT_FRAME_PACKING; } + + SEISegmentedRectFramePacking() {} + virtual ~SEISegmentedRectFramePacking() {} + + Bool m_arrangementCancelFlag; + Int m_contentInterpretationType; + Bool m_arrangementPersistenceFlag; +}; + +class SEIDisplayOrientation : public SEI +{ +public: + PayloadType payloadType() const { return DISPLAY_ORIENTATION; } + + SEIDisplayOrientation() + : cancelFlag(true) + , persistenceFlag(0) + , extensionFlag(false) + {} + virtual ~SEIDisplayOrientation() {} + + Bool cancelFlag; + Bool horFlip; + Bool verFlip; + + UInt anticlockwiseRotation; + Bool persistenceFlag; + Bool extensionFlag; +}; + +class SEITemporalLevel0Index : public SEI +{ +public: + PayloadType payloadType() const { return TEMPORAL_LEVEL0_INDEX; } + + SEITemporalLevel0Index() + : tl0Idx(0) + , rapIdx(0) + {} + virtual ~SEITemporalLevel0Index() {} + + UInt tl0Idx; + UInt rapIdx; +}; + +class SEIGradualDecodingRefreshInfo : public SEI +{ +public: + PayloadType payloadType() const { return REGION_REFRESH_INFO; } + + SEIGradualDecodingRefreshInfo() + : m_gdrForegroundFlag(0) + {} + virtual ~SEIGradualDecodingRefreshInfo() {} + + Bool m_gdrForegroundFlag; +}; + +class SEINoDisplay : public SEI +{ +public: + PayloadType payloadType() const { return NO_DISPLAY; } + + SEINoDisplay() + : m_noDisplay(false) + {} + virtual ~SEINoDisplay() {} + + Bool m_noDisplay; +}; + +class SEISOPDescription : public SEI +{ +public: + PayloadType payloadType() const { return SOP_DESCRIPTION; } + + SEISOPDescription() {} + virtual ~SEISOPDescription() {} + + UInt m_sopSeqParameterSetId; + UInt m_numPicsInSopMinus1; + + UInt m_sopDescVclNaluType[MAX_NUM_PICS_IN_SOP]; + UInt m_sopDescTemporalId[MAX_NUM_PICS_IN_SOP]; + UInt m_sopDescStRpsIdx[MAX_NUM_PICS_IN_SOP]; + Int m_sopDescPocDelta[MAX_NUM_PICS_IN_SOP]; +}; + +class SEIToneMappingInfo : public SEI +{ +public: + PayloadType payloadType() const { return TONE_MAPPING_INFO; } + SEIToneMappingInfo() {} + virtual ~SEIToneMappingInfo() {} + + Int m_toneMapId; + Bool m_toneMapCancelFlag; + Bool m_toneMapPersistenceFlag; + Int m_codedDataBitDepth; + Int m_targetBitDepth; + Int m_modelId; + Int m_minValue; + Int m_maxValue; + Int m_sigmoidMidpoint; + Int m_sigmoidWidth; + std::vector m_startOfCodedInterval; + Int m_numPivots; + std::vector m_codedPivotValue; + std::vector m_targetPivotValue; + Int m_cameraIsoSpeedIdc; + Int m_cameraIsoSpeedValue; + Int m_exposureIndexIdc; + Int m_exposureIndexValue; + Int m_exposureCompensationValueSignFlag; + Int m_exposureCompensationValueNumerator; + Int m_exposureCompensationValueDenomIdc; + Int m_refScreenLuminanceWhite; + Int m_extendedRangeWhiteLevel; + Int m_nominalBlackLevelLumaCodeValue; + Int m_nominalWhiteLevelLumaCodeValue; + Int m_extendedWhiteLevelLumaCodeValue; +}; + +class SEIKneeFunctionInfo : public SEI +{ +public: + PayloadType payloadType() const { return KNEE_FUNCTION_INFO; } + SEIKneeFunctionInfo() {} + virtual ~SEIKneeFunctionInfo() {} + + Int m_kneeId; + Bool m_kneeCancelFlag; + Bool m_kneePersistenceFlag; + Int m_kneeInputDrange; + Int m_kneeInputDispLuminance; + Int m_kneeOutputDrange; + Int m_kneeOutputDispLuminance; + Int m_kneeNumKneePointsMinus1; + std::vector m_kneeInputKneePoint; + std::vector m_kneeOutputKneePoint; +}; + +class SEIChromaSamplingFilterHint : public SEI +{ +public: + PayloadType payloadType() const {return CHROMA_SAMPLING_FILTER_HINT;} + SEIChromaSamplingFilterHint() {} + virtual ~SEIChromaSamplingFilterHint() { + if(m_verChromaFilterIdc == 1) + { + for(Int i = 0; i < m_numVerticalFilters; i ++) + { + free(m_verFilterCoeff[i]); + } + free(m_verFilterCoeff); + free(m_verTapLengthMinus1); + } + if(m_horChromaFilterIdc == 1) + { + for(Int i = 0; i < m_numHorizontalFilters; i ++) + { + free(m_horFilterCoeff[i]); + } + free(m_horFilterCoeff); + free(m_horTapLengthMinus1); + } + } + + Int m_verChromaFilterIdc; + Int m_horChromaFilterIdc; + Bool m_verFilteringProcessFlag; + Int m_targetFormatIdc; + Bool m_perfectReconstructionFlag; + Int m_numVerticalFilters; + Int* m_verTapLengthMinus1; + Int** m_verFilterCoeff; + Int m_numHorizontalFilters; + Int* m_horTapLengthMinus1; + Int** m_horFilterCoeff; +}; + +class SEIMasteringDisplayColourVolume : public SEI +{ +public: + PayloadType payloadType() const { return MASTERING_DISPLAY_COLOUR_VOLUME; } + SEIMasteringDisplayColourVolume() {} + virtual ~SEIMasteringDisplayColourVolume(){} + + TComSEIMasteringDisplay values; +}; + +typedef std::list SEIMessages; + +/// output a selection of SEI messages by payload type. Ownership stays in original message list. +SEIMessages getSeisByType(SEIMessages &seiList, SEI::PayloadType seiType); + +/// remove a selection of SEI messages by payload type from the original list and return them in a new list. +SEIMessages extractSeisByType(SEIMessages &seiList, SEI::PayloadType seiType); + +/// delete list of SEI messages (freeing the referenced objects) +Void deleteSEIs (SEIMessages &seiList); + +class SEIScalableNesting : public SEI +{ +public: + PayloadType payloadType() const { return SCALABLE_NESTING; } + + SEIScalableNesting() {} + virtual ~SEIScalableNesting() + { + if (!m_callerOwnsSEIs) + { + deleteSEIs(m_nestedSEIs); + } + } + + Bool m_bitStreamSubsetFlag; + Bool m_nestingOpFlag; + Bool m_defaultOpFlag; //value valid if m_nestingOpFlag != 0 + UInt m_nestingNumOpsMinus1; // -"- + UInt m_nestingMaxTemporalIdPlus1[MAX_TLAYER]; // -"- + UInt m_nestingOpIdx[MAX_NESTING_NUM_OPS]; // -"- + + Bool m_allLayersFlag; //value valid if m_nestingOpFlag == 0 + UInt m_nestingNoOpMaxTemporalIdPlus1; //value valid if m_nestingOpFlag == 0 and m_allLayersFlag == 0 + UInt m_nestingNumLayersMinus1; //value valid if m_nestingOpFlag == 0 and m_allLayersFlag == 0 + UChar m_nestingLayerId[MAX_NESTING_NUM_LAYER]; //value valid if m_nestingOpFlag == 0 and m_allLayersFlag == 0. This can e.g. be a static array of 64 UChar values + + Bool m_callerOwnsSEIs; + SEIMessages m_nestedSEIs; +}; + +class SEITimeCode : public SEI +{ +public: + PayloadType payloadType() const { return TIME_CODE; } + SEITimeCode() {} + virtual ~SEITimeCode(){} + + UInt numClockTs; + TComSEITimeSet timeSetArray[MAX_TIMECODE_SEI_SETS]; +}; + +//definition according to P1005_v1; +class SEITempMotionConstrainedTileSets: public SEI +{ + struct TileSetData + { + protected: + std::vector m_top_left_tile_index; //[tileSetIdx][tileIdx]; + std::vector m_bottom_right_tile_index; + + public: + Int m_mcts_id; + Bool m_display_tile_set_flag; + Int m_num_tile_rects_in_set; //_minus1; + Bool m_exact_sample_value_match_flag; + Bool m_mcts_tier_level_idc_present_flag; + Bool m_mcts_tier_flag; + Int m_mcts_level_idc; + + Void setNumberOfTileRects(const Int number) + { + m_top_left_tile_index .resize(number); + m_bottom_right_tile_index.resize(number); + } + + Int getNumberOfTileRects() const + { + assert(m_top_left_tile_index.size() == m_bottom_right_tile_index.size()); + return Int(m_top_left_tile_index.size()); + } + + Int &topLeftTileIndex (const Int tileRectIndex) { return m_top_left_tile_index [tileRectIndex]; } + Int &bottomRightTileIndex(const Int tileRectIndex) { return m_bottom_right_tile_index[tileRectIndex]; } + const Int &topLeftTileIndex (const Int tileRectIndex) const { return m_top_left_tile_index [tileRectIndex]; } + const Int &bottomRightTileIndex(const Int tileRectIndex) const { return m_bottom_right_tile_index[tileRectIndex]; } + }; + +protected: + std::vector m_tile_set_data; + +public: + + Bool m_mc_all_tiles_exact_sample_value_match_flag; + Bool m_each_tile_one_tile_set_flag; + Bool m_limited_tile_set_display_flag; + Bool m_max_mcs_tier_level_idc_present_flag; + Bool m_max_mcts_tier_flag; + Int m_max_mcts_level_idc; + + PayloadType payloadType() const { return TEMP_MOTION_CONSTRAINED_TILE_SETS; } + + Void setNumberOfTileSets(const Int number) { m_tile_set_data.resize(number); } + Int getNumberOfTileSets() const { return Int(m_tile_set_data.size()); } + + TileSetData &tileSetData (const Int index) { return m_tile_set_data[index]; } + const TileSetData &tileSetData (const Int index) const { return m_tile_set_data[index]; } + +}; + +#endif + +//! \} diff --git a/jctvc/TLibCommon/TComBitCounter.h b/jctvc/TLibCommon/TComBitCounter.h new file mode 100644 index 0000000..3bd5e86 --- /dev/null +++ b/jctvc/TLibCommon/TComBitCounter.h @@ -0,0 +1,71 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComBitCounter.h + \brief Class for counting bits (header) +*/ + +#ifndef __TCOMBITCOUNTER__ +#define __TCOMBITCOUNTER__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TComBitStream.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// class for counting bits +class TComBitCounter : public TComBitIf +{ +protected: + UInt m_uiBitCounter; + +public: + TComBitCounter() {} + virtual ~TComBitCounter() {} + + Void write ( UInt /*uiBits*/, UInt uiNumberOfBits ) { m_uiBitCounter += uiNumberOfBits; } + Void resetBits () { m_uiBitCounter = 0; } + UInt getNumberOfWrittenBits() const { return m_uiBitCounter; } +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComBitStream.cpp b/jctvc/TLibCommon/TComBitStream.cpp new file mode 100644 index 0000000..c1e3e46 --- /dev/null +++ b/jctvc/TLibCommon/TComBitStream.cpp @@ -0,0 +1,390 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComBitStream.cpp + \brief class for handling bitstream +*/ + +#include +#include +#include "TComBitStream.h" +#include +#include + +using namespace std; + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TComOutputBitstream::TComOutputBitstream() +{ + clear(); +} + +TComOutputBitstream::~TComOutputBitstream() +{ +} + +TComInputBitstream::TComInputBitstream(std::vector* buf) +{ + m_fifo = buf; + m_fifo_idx = 0; + m_held_bits = 0; + m_num_held_bits = 0; + m_numBitsRead = 0; +} + +TComInputBitstream::~TComInputBitstream() +{ +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +Char* TComOutputBitstream::getByteStream() const +{ + return (Char*) &m_fifo.front(); +} + +UInt TComOutputBitstream::getByteStreamLength() +{ + return UInt(m_fifo.size()); +} + +Void TComOutputBitstream::clear() +{ + m_fifo.clear(); + m_held_bits = 0; + m_num_held_bits = 0; +} + +Void TComOutputBitstream::write ( UInt uiBits, UInt uiNumberOfBits ) +{ + assert( uiNumberOfBits <= 32 ); + assert( uiNumberOfBits == 32 || (uiBits & (~0 << uiNumberOfBits)) == 0 ); + + /* any modulo 8 remainder of num_total_bits cannot be written this time, + * and will be held until next time. */ + UInt num_total_bits = uiNumberOfBits + m_num_held_bits; + UInt next_num_held_bits = num_total_bits % 8; + + /* form a byte aligned word (write_bits), by concatenating any held bits + * with the new bits, discarding the bits that will form the next_held_bits. + * eg: H = held bits, V = n new bits /---- next_held_bits + * len(H)=7, len(V)=1: ... ---- HHHH HHHV . 0000 0000, next_num_held_bits=0 + * len(H)=7, len(V)=2: ... ---- HHHH HHHV . V000 0000, next_num_held_bits=1 + * if total_bits < 8, the value of v_ is not used */ + UChar next_held_bits = uiBits << (8 - next_num_held_bits); + + if (!(num_total_bits >> 3)) + { + /* insufficient bits accumulated to write out, append new_held_bits to + * current held_bits */ + /* NB, this requires that v only contains 0 in bit positions {31..n} */ + m_held_bits |= next_held_bits; + m_num_held_bits = next_num_held_bits; + return; + } + + /* topword serves to justify held_bits to align with the msb of uiBits */ + UInt topword = (uiNumberOfBits - next_num_held_bits) & ~((1 << 3) -1); + UInt write_bits = (m_held_bits << topword) | (uiBits >> next_num_held_bits); + + switch (num_total_bits >> 3) + { + case 4: m_fifo.push_back(write_bits >> 24); + case 3: m_fifo.push_back(write_bits >> 16); + case 2: m_fifo.push_back(write_bits >> 8); + case 1: m_fifo.push_back(write_bits); + } + + m_held_bits = next_held_bits; + m_num_held_bits = next_num_held_bits; +} + +Void TComOutputBitstream::writeAlignOne() +{ + UInt num_bits = getNumBitsUntilByteAligned(); + write((1 << num_bits) - 1, num_bits); + return; +} + +Void TComOutputBitstream::writeAlignZero() +{ + if (0 == m_num_held_bits) + { + return; + } + m_fifo.push_back(m_held_bits); + m_held_bits = 0; + m_num_held_bits = 0; +} + +/** + - add substream to the end of the current bitstream + . + \param pcSubstream substream to be added + */ +Void TComOutputBitstream::addSubstream( TComOutputBitstream* pcSubstream ) +{ + UInt uiNumBits = pcSubstream->getNumberOfWrittenBits(); + + const vector& rbsp = pcSubstream->getFIFO(); + for (vector::const_iterator it = rbsp.begin(); it != rbsp.end();) + { + write(*it++, 8); + } + if (uiNumBits&0x7) + { + write(pcSubstream->getHeldBits()>>(8-(uiNumBits&0x7)), uiNumBits&0x7); + } +} + +Void TComOutputBitstream::writeByteAlignment() +{ + write( 1, 1); + writeAlignZero(); +} + +Int TComOutputBitstream::countStartCodeEmulations() +{ + UInt cnt = 0; + vector& rbsp = getFIFO(); + for (vector::iterator it = rbsp.begin(); it != rbsp.end();) + { + vector::iterator found = it; + do + { + // find the next emulated 00 00 {00,01,02,03} + // NB, end()-1, prevents finding a trailing two byte sequence + found = search_n(found, rbsp.end()-1, 2, 0); + found++; + // if not found, found == end, otherwise found = second zero byte + if (found == rbsp.end()) + { + break; + } + if (*(++found) <= 3) + { + break; + } + } while (true); + it = found; + if (found != rbsp.end()) + { + cnt++; + } + } + return cnt; +} + +/** + * read #uiNumberOfBits# from bitstream without updating the bitstream + * state, storing the result in #ruiBits#. + * + * If reading #uiNumberOfBits# would overrun the bitstream buffer, + * the bitsream is effectively padded with sufficient zero-bits to + * avoid the overrun. + */ +Void TComInputBitstream::pseudoRead ( UInt uiNumberOfBits, UInt& ruiBits ) +{ + UInt saved_num_held_bits = m_num_held_bits; + UChar saved_held_bits = m_held_bits; + UInt saved_fifo_idx = m_fifo_idx; + + UInt num_bits_to_read = min(uiNumberOfBits, getNumBitsLeft()); + read(num_bits_to_read, ruiBits); + ruiBits <<= (uiNumberOfBits - num_bits_to_read); + + m_fifo_idx = saved_fifo_idx; + m_held_bits = saved_held_bits; + m_num_held_bits = saved_num_held_bits; +} + + +Void TComInputBitstream::read (UInt uiNumberOfBits, UInt& ruiBits) +{ + assert( uiNumberOfBits <= 32 ); + + m_numBitsRead += uiNumberOfBits; + + /* NB, bits are extracted from the MSB of each byte. */ + UInt retval = 0; + if (uiNumberOfBits <= m_num_held_bits) + { + /* n=1, len(H)=7: -VHH HHHH, shift_down=6, mask=0xfe + * n=3, len(H)=7: -VVV HHHH, shift_down=4, mask=0xf8 + */ + retval = m_held_bits >> (m_num_held_bits - uiNumberOfBits); + retval &= ~(0xff << uiNumberOfBits); + m_num_held_bits -= uiNumberOfBits; + ruiBits = retval; + return; + } + + /* all num_held_bits will go into retval + * => need to mask leftover bits from previous extractions + * => align retval with top of extracted word */ + /* n=5, len(H)=3: ---- -VVV, mask=0x07, shift_up=5-3=2, + * n=9, len(H)=3: ---- -VVV, mask=0x07, shift_up=9-3=6 */ + uiNumberOfBits -= m_num_held_bits; + retval = m_held_bits & ~(0xff << m_num_held_bits); + retval <<= uiNumberOfBits; + + /* number of whole bytes that need to be loaded to form retval */ + /* n=32, len(H)=0, load 4bytes, shift_down=0 + * n=32, len(H)=1, load 4bytes, shift_down=1 + * n=31, len(H)=1, load 4bytes, shift_down=1+1 + * n=8, len(H)=0, load 1byte, shift_down=0 + * n=8, len(H)=3, load 1byte, shift_down=3 + * n=5, len(H)=1, load 1byte, shift_down=1+3 + */ + UInt aligned_word = 0; + UInt num_bytes_to_load = (uiNumberOfBits - 1) >> 3; + assert(m_fifo_idx + num_bytes_to_load < m_fifo->size()); + + switch (num_bytes_to_load) + { + case 3: aligned_word = (*m_fifo)[m_fifo_idx++] << 24; + case 2: aligned_word |= (*m_fifo)[m_fifo_idx++] << 16; + case 1: aligned_word |= (*m_fifo)[m_fifo_idx++] << 8; + case 0: aligned_word |= (*m_fifo)[m_fifo_idx++]; + } + + /* resolve remainder bits */ + UInt next_num_held_bits = (32 - uiNumberOfBits) % 8; + + /* copy required part of aligned_word into retval */ + retval |= aligned_word >> next_num_held_bits; + + /* store held bits */ + m_num_held_bits = next_num_held_bits; + m_held_bits = aligned_word; + + ruiBits = retval; +} + +/** + * insert the contents of the bytealigned (and flushed) bitstream src + * into this at byte position pos. + */ +Void TComOutputBitstream::insertAt(const TComOutputBitstream& src, UInt pos) +{ + UInt src_bits = src.getNumberOfWrittenBits(); + assert(0 == src_bits % 8); + + vector::iterator at = m_fifo.begin() + pos; + m_fifo.insert(at, src.m_fifo.begin(), src.m_fifo.end()); +} + +UInt TComInputBitstream::readOutTrailingBits () +{ + UInt count=0; + UInt uiBits = 0; + + while ( ( getNumBitsLeft() > 0 ) && (getNumBitsUntilByteAligned()!=0) ) + { + count++; + read ( 1, uiBits ); + } + return count; +} +// +//TComOutputBitstream& TComOutputBitstream::operator= (const TComOutputBitstream& src) +//{ +// vector::iterator at = m_fifo.begin(); +// m_fifo.insert(at, src.m_fifo.begin(), src.m_fifo.end()); +// +// m_num_held_bits = src.m_num_held_bits; +// m_held_bits = src.m_held_bits; +// +// return *this; +//} + +/** + - extract substream from the current bitstream + . + \param pcBitstream bitstream which contains substreams + \param uiNumBits number of bits to transfer + */ +TComInputBitstream *TComInputBitstream::extractSubstream( UInt uiNumBits ) +{ + UInt uiNumBytes = uiNumBits/8; + std::vector* buf = new std::vector; + UInt uiByte; + for (UInt ui = 0; ui < uiNumBytes; ui++) + { + read(8, uiByte); + buf->push_back(uiByte); + } + if (uiNumBits&0x7) + { + uiByte = 0; + read(uiNumBits&0x7, uiByte); + uiByte <<= 8-(uiNumBits&0x7); + buf->push_back(uiByte); + } + return new TComInputBitstream(buf); +} + +/** + - delete internal fifo + */ +Void TComInputBitstream::deleteFifo() +{ + delete m_fifo; + m_fifo = NULL; +} + +UInt TComInputBitstream::readByteAlignment() +{ + UInt code = 0; + read( 1, code ); + assert(code == 1); + + UInt numBits = getNumBitsUntilByteAligned(); + if(numBits) + { + assert(numBits <= getNumBitsLeft()); + read( numBits, code ); + assert(code == 0); + } + return numBits+1; +} + +//! \} diff --git a/jctvc/TLibCommon/TComBitStream.h b/jctvc/TLibCommon/TComBitStream.h new file mode 100644 index 0000000..8d5ec00 --- /dev/null +++ b/jctvc/TLibCommon/TComBitStream.h @@ -0,0 +1,228 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComBitStream.h + \brief class for handling bitstream (header) +*/ + +#ifndef __TCOMBITSTREAM__ +#define __TCOMBITSTREAM__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include +#include +#include +#include "CommonDef.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// pure virtual class for basic bit handling +class TComBitIf +{ +public: + virtual Void writeAlignOne () {}; + virtual Void writeAlignZero () {}; + virtual Void write ( UInt uiBits, UInt uiNumberOfBits ) = 0; + virtual Void resetBits () = 0; + virtual UInt getNumberOfWrittenBits() const = 0; + virtual ~TComBitIf() {} +}; + +/** + * Model of a writable bitstream that accumulates bits to produce a + * bytestream. + */ +class TComOutputBitstream : public TComBitIf +{ + /** + * FIFO for storage of bytes. Use: + * - fifo.push_back(x) to append words + * - fifo.clear() to empty the FIFO + * - &fifo.front() to get a pointer to the data array. + * NB, this pointer is only valid until the next push_back()/clear() + */ + std::vector m_fifo; + + UInt m_num_held_bits; /// number of bits not flushed to bytestream. + UChar m_held_bits; /// the bits held and not flushed to bytestream. + /// this value is always msb-aligned, bigendian. +public: + // create / destroy + TComOutputBitstream(); + ~TComOutputBitstream(); + + // interface for encoding + /** + * append uiNumberOfBits least significant bits of uiBits to + * the current bitstream + */ + Void write ( UInt uiBits, UInt uiNumberOfBits ); + + /** insert one bits until the bitstream is byte-aligned */ + Void writeAlignOne (); + + /** insert zero bits until the bitstream is byte-aligned */ + Void writeAlignZero (); + + /** this function should never be called */ + Void resetBits() { assert(0); } + + // utility functions + + /** + * Return a pointer to the start of the byte-stream buffer. + * Pointer is valid until the next write/flush/reset call. + * NB, data is arranged such that subsequent bytes in the + * bytestream are stored in ascending addresses. + */ + Char* getByteStream() const; + + /** + * Return the number of valid bytes available from getByteStream() + */ + UInt getByteStreamLength(); + + /** + * Reset all internal state. + */ + Void clear(); + + /** + * returns the number of bits that need to be written to + * achieve byte alignment. + */ + Int getNumBitsUntilByteAligned() { return (8 - m_num_held_bits) & 0x7; } + + /** + * Return the number of bits that have been written since the last clear() + */ + UInt getNumberOfWrittenBits() const { return UInt(m_fifo.size()) * 8 + m_num_held_bits; } + + Void insertAt(const TComOutputBitstream& src, UInt pos); + + /** + * Return a reference to the internal fifo + */ + std::vector& getFIFO() { return m_fifo; } + + UChar getHeldBits () { return m_held_bits; } + + //TComOutputBitstream& operator= (const TComOutputBitstream& src); + /** Return a reference to the internal fifo */ + const std::vector& getFIFO() const { return m_fifo; } + + Void addSubstream ( TComOutputBitstream* pcSubstream ); + Void writeByteAlignment(); + + //! returns the number of start code emulations contained in the current buffer + Int countStartCodeEmulations(); +}; + +/** + * Model of an input bitstream that extracts bits from a predefined + * bytestream. + */ +class TComInputBitstream +{ + std::vector *m_fifo; /// FIFO for storage of complete bytes + std::vector m_emulationPreventionByteLocation; + +protected: + UInt m_fifo_idx; /// Read index into m_fifo + + UInt m_num_held_bits; + UChar m_held_bits; + UInt m_numBitsRead; + +public: + /** + * Create a new bitstream reader object that reads from #buf#. Ownership + * of #buf# remains with the callee, although the constructed object + * will hold a reference to #buf# + */ + TComInputBitstream(std::vector* buf); + ~TComInputBitstream(); + + // interface for decoding + Void pseudoRead ( UInt uiNumberOfBits, UInt& ruiBits ); + Void read ( UInt uiNumberOfBits, UInt& ruiBits ); + Void readByte ( UInt &ruiBits ) + { + assert(m_fifo_idx < m_fifo->size()); + ruiBits = (*m_fifo)[m_fifo_idx++]; + } + + Void peekPreviousByte( UInt &byte ) + { + assert(m_fifo_idx > 0); + byte = (*m_fifo)[m_fifo_idx - 1]; + } + + UInt readOutTrailingBits (); + UChar getHeldBits () { return m_held_bits; } + TComOutputBitstream& operator= (const TComOutputBitstream& src); + UInt getByteLocation ( ) { return m_fifo_idx ; } + + // Peek at bits in word-storage. Used in determining if we have completed reading of current bitstream and therefore slice in LCEC. + UInt peekBits (UInt uiBits) { UInt tmp; pseudoRead(uiBits, tmp); return tmp; } + + // utility functions + UInt read(UInt numberOfBits) { UInt tmp; read(numberOfBits, tmp); return tmp; } + UInt readByte() { UInt tmp; readByte( tmp ); return tmp; } + UInt getNumBitsUntilByteAligned() { return m_num_held_bits & (0x7); } + UInt getNumBitsLeft() { return 8*((UInt)m_fifo->size() - m_fifo_idx) + m_num_held_bits; } + TComInputBitstream *extractSubstream( UInt uiNumBits ); // Read the nominated number of bits, and return as a bitstream. + Void deleteFifo(); // Delete internal fifo of bitstream. + UInt getNumBitsRead() { return m_numBitsRead; } + UInt readByteAlignment(); + + Void pushEmulationPreventionByteLocation ( UInt pos ) { m_emulationPreventionByteLocation.push_back( pos ); } + UInt numEmulationPreventionBytesRead () { return (UInt) m_emulationPreventionByteLocation.size(); } + std::vector getEmulationPreventionByteLocation () { return m_emulationPreventionByteLocation; } + UInt getEmulationPreventionByteLocation ( UInt idx ) { return m_emulationPreventionByteLocation[ idx ]; } + Void clearEmulationPreventionByteLocation() { m_emulationPreventionByteLocation.clear(); } + Void setEmulationPreventionByteLocation ( std::vector vec ) { m_emulationPreventionByteLocation = vec; } +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComCABACTables.cpp b/jctvc/TLibCommon/TComCABACTables.cpp new file mode 100644 index 0000000..59f2581 --- /dev/null +++ b/jctvc/TLibCommon/TComCABACTables.cpp @@ -0,0 +1,123 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComCABACTables.cpp + * \brief static class for CABAC tables + */ + +#include "TComCABACTables.h" + +//! \ingroup TLibCommon +//! \{ + +const UChar TComCABACTables::sm_aucLPSTable[1 << CONTEXT_STATE_BITS][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} +}; + +const UChar TComCABACTables::sm_aucRenormTable[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 +}; + +//! \} diff --git a/jctvc/TLibCommon/TComCABACTables.h b/jctvc/TLibCommon/TComCABACTables.h new file mode 100644 index 0000000..57b66ca --- /dev/null +++ b/jctvc/TLibCommon/TComCABACTables.h @@ -0,0 +1,61 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComCABACTables.h + \brief static class for CABAC tables +*/ + +#ifndef __TCOMCABACTABLES__ +#define __TCOMCABACTABLES__ + +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComRom.h" + +//! \ingroup TLibCommon +//! \{ + +/** + * \brief static class for CABAC tables + */ + +class TComCABACTables +{ +public: + const static UChar sm_aucLPSTable[1 << CONTEXT_STATE_BITS][4]; + const static UChar sm_aucRenormTable[32]; +}; + + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComChromaFormat.cpp b/jctvc/TLibCommon/TComChromaFormat.cpp new file mode 100644 index 0000000..ee6fb74 --- /dev/null +++ b/jctvc/TLibCommon/TComChromaFormat.cpp @@ -0,0 +1,142 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "TComChromaFormat.h" +#include "TComPic.h" +#include "TComDataCU.h" +#include "TComTrQuant.h" +#include "TComTU.h" + + + + +//---------------------------------------------------------------------------------------------------------------------- + +InputColourSpaceConversion stringToInputColourSpaceConvert(const std::string &value, const Bool bIsForward) +{ + if (value.empty() || value=="UNCHANGED") return IPCOLOURSPACE_UNCHANGED; + if (bIsForward) + { + if (value=="YCbCrtoYYY") return IPCOLOURSPACE_YCbCrtoYYY; + if (value=="YCbCrtoYCrCb") return IPCOLOURSPACE_YCbCrtoYCrCb; + if (value=="RGBtoGBR") return IPCOLOURSPACE_RGBtoGBR; + } + else + { + if (value=="YCrCbtoYCbCr") return IPCOLOURSPACE_YCbCrtoYCrCb; + if (value=="GBRtoRGB") return IPCOLOURSPACE_RGBtoGBR; + } + return NUMBER_INPUT_COLOUR_SPACE_CONVERSIONS; +} + +std::string getListOfColourSpaceConverts(const Bool bIsForward) +{ + if (bIsForward) + { + return "UNCHANGED, YCbCrtoYCrCb, YCbCrtoYYY or RGBtoGBR"; + } + else + { + return "UNCHANGED, YCrCbtoYCbCr or GBRtoRGB"; + } +} + + +//---------------------------------------------------------------------------------------------------------------------- + +Void getTUEntropyCodingParameters( TUEntropyCodingParameters &result, + TComTU &rTu, + const ComponentID component) +{ + //------------------------------------------------ + + //set the local parameters + + TComDataCU *const pcCU = rTu.getCU(); + const TComRectangle & area = rTu.getRect(component); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(component); + const UInt log2BlockWidth = g_aucConvertToBit[area.width] + 2; + const UInt log2BlockHeight = g_aucConvertToBit[area.height] + 2; + const ChannelType channelType = toChannelType(component); + + result.scanType = COEFF_SCAN_TYPE(pcCU->getCoefScanIdx(uiAbsPartIdx, area.width, area.height, component)); + + //------------------------------------------------ + + //set the group layout + + result.widthInGroups = area.width >> MLS_CG_LOG2_WIDTH; + result.heightInGroups = area.height >> MLS_CG_LOG2_HEIGHT; + + //------------------------------------------------ + + //set the scan orders + + const UInt log2WidthInGroups = g_aucConvertToBit[result.widthInGroups * 4]; + const UInt log2HeightInGroups = g_aucConvertToBit[result.heightInGroups * 4]; + + result.scan = g_scanOrder[ SCAN_GROUPED_4x4 ][ result.scanType ][ log2BlockWidth ][ log2BlockHeight ]; + result.scanCG = g_scanOrder[ SCAN_UNGROUPED ][ result.scanType ][ log2WidthInGroups ][ log2HeightInGroups ]; + + //------------------------------------------------ + + //set the significance map context selection parameters + + if (pcCU->getSlice()->getSPS()->getUseSingleSignificanceMapContext() + && (pcCU->getCUTransquantBypass(uiAbsPartIdx) || (pcCU->getTransformSkip(uiAbsPartIdx, component) != 0))) + { + result.firstSignificanceMapContext = significanceMapContextSetStart[channelType][CONTEXT_TYPE_SINGLE]; + } + else + { + if ((area.width == 4) && (area.height == 4)) + { + result.firstSignificanceMapContext = significanceMapContextSetStart[channelType][CONTEXT_TYPE_4x4]; + } + else if ((area.width == 8) && (area.height == 8)) + { + result.firstSignificanceMapContext = significanceMapContextSetStart[channelType][CONTEXT_TYPE_8x8]; + if (result.scanType != SCAN_DIAG) result.firstSignificanceMapContext += nonDiagonalScan8x8ContextOffset[channelType]; + } + else + { + result.firstSignificanceMapContext = significanceMapContextSetStart[channelType][CONTEXT_TYPE_NxN]; + } + } + + //------------------------------------------------ +} + + +//---------------------------------------------------------------------------------------------------------------------- diff --git a/jctvc/TLibCommon/TComChromaFormat.h b/jctvc/TLibCommon/TComChromaFormat.h new file mode 100644 index 0000000..3e3f598 --- /dev/null +++ b/jctvc/TLibCommon/TComChromaFormat.h @@ -0,0 +1,277 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TCOMCHROMAFORMAT__ +#define __TCOMCHROMAFORMAT__ + +#include "CommonDef.h" +#include "TComRectangle.h" +#include "ContextTables.h" +#include "TComRom.h" +#include +#include +#include +#include "Debug.h" + +//====================================================================================================================== +//Chroma format utility functions ===================================================================================== +//====================================================================================================================== + +class TComDataCU; + + +static inline ChannelType toChannelType (const ComponentID id) { return (id==COMPONENT_Y)? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA; } +static inline Bool isLuma (const ComponentID id) { return (id==COMPONENT_Y); } +static inline Bool isLuma (const ChannelType id) { return (id==CHANNEL_TYPE_LUMA); } +static inline Bool isChroma (const ComponentID id) { return (id!=COMPONENT_Y); } +static inline Bool isChroma (const ChannelType id) { return (id!=CHANNEL_TYPE_LUMA); } +static inline UInt getChannelTypeScaleX (const ChannelType id, const ChromaFormat fmt) { return (isLuma(id) || (fmt==CHROMA_444)) ? 0 : 1; } +static inline UInt getChannelTypeScaleY (const ChannelType id, const ChromaFormat fmt) { return (isLuma(id) || (fmt!=CHROMA_420)) ? 0 : 1; } +static inline UInt getComponentScaleX (const ComponentID id, const ChromaFormat fmt) { return getChannelTypeScaleX(toChannelType(id), fmt); } +static inline UInt getComponentScaleY (const ComponentID id, const ChromaFormat fmt) { return getChannelTypeScaleY(toChannelType(id), fmt); } +static inline UInt getNumberValidChannelTypes(const ChromaFormat fmt) { return (fmt==CHROMA_400) ? 1 : MAX_NUM_CHANNEL_TYPE; } +static inline UInt getNumberValidComponents (const ChromaFormat fmt) { return (fmt==CHROMA_400) ? 1 : MAX_NUM_COMPONENT; } +static inline Bool isChromaEnabled (const ChromaFormat fmt) { return fmt!=CHROMA_400; } +static inline ComponentID getFirstComponentOfChannel(const ChannelType id) { return (isLuma(id) ? COMPONENT_Y : COMPONENT_Cb); } + +InputColourSpaceConversion stringToInputColourSpaceConvert(const std::string &value, const Bool bIsForward); +std::string getListOfColourSpaceConverts(const Bool bIsForward); + +//------------------------------------------------ + +static inline UInt getTotalSamples(const UInt width, const UInt height, const ChromaFormat format) +{ + const UInt samplesPerChannel = width * height; + + switch (format) + { + case CHROMA_400: return samplesPerChannel; break; + case CHROMA_420: return (samplesPerChannel * 3) >> 1; break; + case CHROMA_422: return samplesPerChannel * 2; break; + case CHROMA_444: return samplesPerChannel * 3; break; + default: + std::cerr << "ERROR: Unrecognised chroma format in getTotalSamples()" << std::endl; + exit(1); + break; + } + + return MAX_UINT; +} + +//------------------------------------------------ + +static inline UInt getTotalBits(const UInt width, const UInt height, const ChromaFormat format, const Int bitDepths[MAX_NUM_CHANNEL_TYPE]) +{ + const UInt samplesPerChannel = width * height; + + switch (format) + { + case CHROMA_400: return samplesPerChannel * bitDepths[CHANNEL_TYPE_LUMA]; break; + case CHROMA_420: return (samplesPerChannel * (bitDepths[CHANNEL_TYPE_LUMA]*2 + bitDepths[CHANNEL_TYPE_CHROMA]) ) >> 1; break; + case CHROMA_422: return samplesPerChannel * (bitDepths[CHANNEL_TYPE_LUMA] + bitDepths[CHANNEL_TYPE_CHROMA]); break; + case CHROMA_444: return samplesPerChannel * (bitDepths[CHANNEL_TYPE_LUMA] + 2*bitDepths[CHANNEL_TYPE_CHROMA]); break; + default: + std::cerr << "ERROR: Unrecognised chroma format in getTotalSamples()" << std::endl; + exit(1); + break; + } + + return MAX_UINT; +} + + +//------------------------------------------------ + +// In HM, a CU only has one chroma intra prediction direction, that corresponds to the top left luma intra prediction +// even if the NxN PU split occurs when 4 sub-TUs exist for chroma. +// Use this function to allow NxN PU splitting for chroma. + +static inline Bool enable4ChromaPUsInIntraNxNCU(const ChromaFormat chFmt) +{ + return (chFmt == CHROMA_444); +} + + +//------------------------------------------------ + +//returns the part index of the luma region that is co-located with the specified chroma region + +static inline UInt getChromasCorrespondingPULumaIdx(const UInt lumaZOrderIdxInCtu, const ChromaFormat chFmt) +{ + return enable4ChromaPUsInIntraNxNCU(chFmt) ? lumaZOrderIdxInCtu : lumaZOrderIdxInCtu & (~((1<<(2*g_uiAddCUDepth))-1)); //(lumaZOrderIdxInCtu/numParts)*numParts; +} + +//------------------------------------------------ + +// If chroma format is 4:2:2 and a chroma-square-sub-tu is possible for the smallest TU, then increase the depth by 1 to allow for more parts. + +static inline UInt getMaxCUDepthOffset(const ChromaFormat chFmt, const UInt quadtreeTULog2MinSize) +{ + return (chFmt==CHROMA_422 && quadtreeTULog2MinSize>2) ? 1 : 0; +} + +//====================================================================================================================== +//Intra prediction ==================================================================================================== +//====================================================================================================================== + +static inline Bool filterIntraReferenceSamples (const ChannelType chType, const ChromaFormat chFmt, const Bool intraReferenceSmoothingDisabled) +{ + return (!intraReferenceSmoothingDisabled) && (isLuma(chType) || (chFmt == CHROMA_444)); +} + + +//====================================================================================================================== +//Transform and Quantisation ========================================================================================== +//====================================================================================================================== + +static inline Bool TUCompRectHasAssociatedTransformSkipFlag(const TComRectangle &rectSamples, const UInt transformSkipLog2MaxSize) +{ + return (rectSamples.width <= (1<> 2)); + result_offsetY = (isChroma(component)) ? 0 : ((convertedHeight * 3) + ((convertedHeight + 1) >> 2)); + result_shiftX = (isChroma(component)) ? convertedWidth : ((convertedWidth + 3) >> 2); + result_shiftY = (isChroma(component)) ? convertedHeight : ((convertedHeight + 3) >> 2); +} + + +//------------------------------------------------ + +//Function for significance map context index offset selection + +static inline UInt getSignificanceMapContextOffset (const ComponentID component) +{ + return significanceMapContextStartTable[toChannelType(component)]; +} + + +//------------------------------------------------ + +// Function for greater-than-one map/greater-than-two map context set selection + +static inline UInt getContextSetIndex (const ComponentID component, + const UInt subsetIndex, + const Bool foundACoefficientGreaterThan1) +{ + const UInt notFirstSubsetOffset = (isLuma(component) && (subsetIndex > 0)) ? 2 : 0; + const UInt foundAGreaterThan1Offset = foundACoefficientGreaterThan1 ? 1 : 0; + + return contextSetStartTable[toChannelType(component)] + notFirstSubsetOffset + foundAGreaterThan1Offset; +} + + +//------------------------------------------------ + +//Function for CBF context index offset + +static inline UInt getCBFContextOffset (const ComponentID component) +{ + return CBFContextStartTable[toChannelType(component)]; +} + + +//====================================================================================================================== +//Entropy coding parameters ============================================================================================ +//====================================================================================================================== + +Void getTUEntropyCodingParameters( TUEntropyCodingParameters &result, + class TComTU &rTu, + const ComponentID component); + + +//====================================================================================================================== +//End ================================================================================================================= +//====================================================================================================================== + +#endif diff --git a/jctvc/TLibCommon/TComCodingStatistics.h b/jctvc/TLibCommon/TComCodingStatistics.h new file mode 100644 index 0000000..d999008 --- /dev/null +++ b/jctvc/TLibCommon/TComCodingStatistics.h @@ -0,0 +1,470 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TCOMCODINGSTATISTICS__ +#define __TCOMCODINGSTATISTICS__ + +#include "TypeDef.h" +#include +#include +#include +#include +#include "TComChromaFormat.h" + +static const Int64 TCOMCODINGSTATISTICS_ENTROPYSCALE=32768; + + +enum TComCodingStatisticsType +{ + STATS__NAL_UNIT_TOTAL_BODY,// This is a special case and is not included in the total sums. + STATS__NAL_UNIT_PACKING, + STATS__EMULATION_PREVENTION_3_BYTES, + STATS__NAL_UNIT_HEADER_BITS, + STATS__CABAC_INITIALISATION, + STATS__CABAC_BITS__TQ_BYPASS_FLAG, + STATS__CABAC_BITS__SKIP_FLAG, + STATS__CABAC_BITS__MERGE_FLAG, + STATS__CABAC_BITS__MERGE_INDEX, + STATS__CABAC_BITS__MVP_IDX, + STATS__CABAC_BITS__SPLIT_FLAG, + STATS__CABAC_BITS__PART_SIZE, + STATS__CABAC_BITS__PRED_MODE, + STATS__CABAC_BITS__INTRA_DIR_ANG, + STATS__CABAC_BITS__INTER_DIR, + STATS__CABAC_BITS__REF_FRM_IDX, + STATS__CABAC_BITS__MVD, + STATS__CABAC_BITS__MVD_EP, + STATS__CABAC_BITS__TRANSFORM_SUBDIV_FLAG, + STATS__CABAC_BITS__QT_ROOT_CBF, + STATS__CABAC_BITS__DELTA_QP_EP, + STATS__CABAC_BITS__CHROMA_QP_ADJUSTMENT, + STATS__CABAC_BITS__QT_CBF, + STATS__CABAC_BITS__CROSS_COMPONENT_PREDICTION, + STATS__CABAC_BITS__TRANSFORM_SKIP_FLAGS, + + STATS__CABAC_BITS__LAST_SIG_X_Y, + STATS__CABAC_BITS__SIG_COEFF_GROUP_FLAG, + STATS__CABAC_BITS__SIG_COEFF_MAP_FLAG, + STATS__CABAC_BITS__GT1_FLAG, + STATS__CABAC_BITS__GT2_FLAG, + STATS__CABAC_BITS__SIGN_BIT, + STATS__CABAC_BITS__ESCAPE_BITS, + + STATS__CABAC_BITS__SAO, + STATS__CABAC_TRM_BITS, + STATS__CABAC_FIXED_BITS, + STATS__CABAC_PCM_ALIGN_BITS, + STATS__CABAC_PCM_CODE_BITS, + STATS__BYTE_ALIGNMENT_BITS, + STATS__TRAILING_BITS, + STATS__EXPLICIT_RDPCM_BITS, + STATS__CABAC_EP_BIT_ALIGNMENT, + STATS__CABAC_BITS__ALIGNED_SIGN_BIT, + STATS__CABAC_BITS__ALIGNED_ESCAPE_BITS, + STATS__NUM_STATS +}; + +static inline const Char* getName(TComCodingStatisticsType name) +{ + static const Char *statNames[]= + { + "NAL_UNIT_TOTAL_BODY", // This is a special case and is not included in the total sums. + "NAL_UNIT_PACKING", + "EMULATION_PREVENTION_3_BYTES", + "NAL_UNIT_HEADER_BITS", + "CABAC_INITIALISATION-and-rounding", + "CABAC_BITS__TQ_BYPASS_FLAG", + "CABAC_BITS__SKIP_FLAG", + "CABAC_BITS__MERGE_FLAG", + "CABAC_BITS__MERGE_INDEX", + "CABAC_BITS__MVP_IDX", + "CABAC_BITS__SPLIT_FLAG", + "CABAC_BITS__PART_SIZE", + "CABAC_BITS__PRED_MODE", + "CABAC_BITS__INTRA_DIR_ANG", + "CABAC_BITS__INTER_DIR", + "CABAC_BITS__REF_FRM_IDX", + "CABAC_BITS__MVD", + "CABAC_BITS__MVD_EP", + "CABAC_BITS__TRANSFORM_SUBDIV_FLAG", + "CABAC_BITS__QT_ROOT_CBF", + "CABAC_BITS__DELTA_QP_EP", + "CABAC_BITS__CHROMA_QP_ADJUSTMENT", + "CABAC_BITS__QT_CBF", + "CABAC_BITS__CROSS_COMPONENT_PREDICTION", + "CABAC_BITS__TRANSFORM_SKIP_FLAGS", + "CABAC_BITS__LAST_SIG_X_Y", + "CABAC_BITS__SIG_COEFF_GROUP_FLAG", + "CABAC_BITS__SIG_COEFF_MAP_FLAG", + "CABAC_BITS__GT1_FLAG", + "CABAC_BITS__GT2_FLAG", + "CABAC_BITS__SIGN_BIT", + "CABAC_BITS__ESCAPE_BITS", + "CABAC_BITS__SAO", + "CABAC_TRM_BITS", + "CABAC_FIXED_BITS", + "CABAC_PCM_ALIGN_BITS", + "CABAC_PCM_CODE_BITS", + "BYTE_ALIGNMENT_BITS", + "TRAILING_BITS", + "EXPLICIT_RDPCM_BITS", + "CABAC_EP_BIT_ALIGNMENT", + "CABAC_BITS__ALIGNED_SIGN_BIT", + "CABAC_BITS__ALIGNED_ESCAPE_BITS" + }; + assert(STATS__NUM_STATS == sizeof(statNames)/sizeof(Char *) && name < STATS__NUM_STATS); + return statNames[name]; +} + +static inline Bool isAlignedBins(TComCodingStatisticsType statT) { return statT==STATS__CABAC_BITS__ALIGNED_SIGN_BIT || statT==STATS__CABAC_BITS__ALIGNED_ESCAPE_BITS; } + +static const UInt CODING_STATS_NUM_WIDTHS=7; +static const UInt CODING_STATS_NUM_SUBCLASSES=CODING_STATS_NUM_WIDTHS*(1+MAX_NUM_COMPONENT+MAX_NUM_CHANNEL_TYPE); + +class TComCodingStatisticsClassType +{ +public: + + TComCodingStatisticsClassType(const TComCodingStatisticsType t) + : type(t), subClass(0) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const UInt log2w ) + : type(t), subClass(log2w) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const Int log2w ) + : type(t), subClass(log2w) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const ComponentID cid ) + : type(t), subClass((cid+1)*CODING_STATS_NUM_WIDTHS) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const ChannelType chid ) + : type(t), subClass((chid+MAX_NUM_COMPONENT+1)*CODING_STATS_NUM_WIDTHS) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const UInt log2w, const ComponentID cid ) + : type(t), subClass((cid+1)*CODING_STATS_NUM_WIDTHS + log2w) + { } + TComCodingStatisticsClassType(const TComCodingStatisticsType t, const UInt log2w, const ChannelType chid ) + : type(t), subClass((chid+MAX_NUM_COMPONENT+1)*CODING_STATS_NUM_WIDTHS + log2w) + { } + + static UInt GetSubClassWidth(const UInt subClass) + { + return subClass%CODING_STATS_NUM_WIDTHS; + } + + static const Char *GetSubClassString(const UInt subClass) + { + assert (subClass mappings_ep; + friend class TComCodingStatistics; + }; + + private: + + TComCodingStatisticsData data; + + TComCodingStatistics() : data() + { } + + static Void OutputLine(const Char *pName, const Char sep, UInt width, const Char *pSubClassStr, const SStat &sCABAC, const SStat &sEP) + { + if (width==0) + OutputLine(pName, sep, "-", pSubClassStr, sCABAC, sEP); + else + printf("%c%-45s%c %6d %6s %12lld %12lld %12lld %12lld %12lld %12lld %12lld (%12lld)%c\n", + sep=='~'?'[':' ', pName, sep, 1<::iterator it=data.mappings_ep.begin(); it!=data.mappings_ep.end(); it++) + { + SStat s=it->second; + cavlcTotalBits+=s; + OutputLine(it->first.c_str(), ':', "-", "-", s); + } + + OutputDashedLine(""); + OutputLine("CAVLC Header Sub-total", '~', "~~ST~~", "~~ST~~", cavlcTotalBits); + + // Now output the breakdowns + OutputDashedLine("CABAC Break down by size"); + for(UInt s=0; s> chromaShift; + + m_crossComponentPredictionAlpha[compID] = (Char* )xMalloc(Char, uiNumPartition); + m_puhTransformSkip[compID] = (UChar* )xMalloc(UChar, uiNumPartition); + m_explicitRdpcmMode[compID] = (UChar* )xMalloc(UChar, uiNumPartition); + m_puhCbf[compID] = (UChar* )xMalloc(UChar, uiNumPartition); + m_pcTrCoeff[compID] = (TCoeff*)xMalloc(TCoeff, totalSize); + memset( m_pcTrCoeff[compID], 0, (totalSize * sizeof( TCoeff )) ); + +#if ADAPTIVE_QP_SELECTION + if( bGlobalRMARLBuffer ) + { + if (m_pcGlbArlCoeff[compID] == NULL) m_pcGlbArlCoeff[compID] = (TCoeff*)xMalloc(TCoeff, totalSize); + + m_pcArlCoeff[compID] = m_pcGlbArlCoeff[compID]; + m_ArlCoeffIsAliasedAllocation = true; + } + else + { + m_pcArlCoeff[compID] = (TCoeff*)xMalloc(TCoeff, totalSize); + } +#endif + m_pcIPCMSample[compID] = (Pel* )xMalloc(Pel , totalSize); + } + + m_pbIPCMFlag = (Bool* )xMalloc(Bool, uiNumPartition); + + for(UInt i=0; igetSlice() != NULL && + m_pcPic->getPicSym()->getTileIdxMap( pCU->getCtuRsAddr() ) == m_pcPic->getPicSym()->getTileIdxMap(getCtuRsAddr()); +} + +Bool TComDataCU::CUIsFromSameSliceAndTile ( const TComDataCU *pCU /* Can be NULL */) const +{ + return pCU!=NULL && + pCU->getSlice() != NULL && + pCU->getSlice()->getSliceCurStartCtuTsAddr() == getSlice()->getSliceCurStartCtuTsAddr() && + m_pcPic->getPicSym()->getTileIdxMap( pCU->getCtuRsAddr() ) == m_pcPic->getPicSym()->getTileIdxMap(getCtuRsAddr()) + ; +} + +Bool TComDataCU::CUIsFromSameSliceTileAndWavefrontRow( const TComDataCU *pCU /* Can be NULL */) const +{ + return CUIsFromSameSliceAndTile(pCU) + && (!getSlice()->getPPS()->getEntropyCodingSyncEnabledFlag() || getPic()->getCtu(getCtuRsAddr())->getCUPelY() == getPic()->getCtu(pCU->getCtuRsAddr())->getCUPelY()); +} + +Bool TComDataCU::isLastSubCUOfCtu(const UInt absPartIdx) +{ + TComPic* pcPic = getPic(); + TComSlice * pcSlice = pcPic->getSlice(pcPic->getCurrSliceIdx()); + + const UInt picWidth = pcSlice->getSPS()->getPicWidthInLumaSamples(); + const UInt picHeight = pcSlice->getSPS()->getPicHeightInLumaSamples(); + const UInt granularityWidth = g_uiMaxCUWidth; + + const UInt cuPosX = getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[absPartIdx] ]; + const UInt cuPosY = getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[absPartIdx] ]; + + return (((cuPosX+getWidth( absPartIdx))%granularityWidth==0||(cuPosX+getWidth( absPartIdx)==picWidth )) + && ((cuPosY+getHeight(absPartIdx))%granularityWidth==0||(cuPosY+getHeight(absPartIdx)==picHeight))); +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +// -------------------------------------------------------------------------------------------------------------------- +// Initialization +// -------------------------------------------------------------------------------------------------------------------- + +/** + - initialize top-level CU + - internal buffers are already created + - set values before encoding a CU + . + \param pcPic picture (TComPic) class pointer + \param iCUAddr CU address + */ +Void TComDataCU::initCtu( TComPic* pcPic, UInt ctuRsAddr ) +{ + + m_pcPic = pcPic; + m_pcSlice = pcPic->getSlice(pcPic->getCurrSliceIdx()); + m_ctuRsAddr = ctuRsAddr; + m_uiCUPelX = ( ctuRsAddr % pcPic->getFrameWidthInCtus() ) * g_uiMaxCUWidth; + m_uiCUPelY = ( ctuRsAddr / pcPic->getFrameWidthInCtus() ) * g_uiMaxCUHeight; + m_absZIdxInCtu = 0; + m_dTotalCost = MAX_DOUBLE; + m_uiTotalDistortion = 0; + m_uiTotalBits = 0; + m_uiTotalBins = 0; + m_uiNumPartition = pcPic->getNumPartitionsInCtu(); + + memset( m_skipFlag , false, m_uiNumPartition * sizeof( *m_skipFlag ) ); + + memset( m_pePartSize , NUMBER_OF_PART_SIZES, m_uiNumPartition * sizeof( *m_pePartSize ) ); + memset( m_pePredMode , NUMBER_OF_PREDICTION_MODES, m_uiNumPartition * sizeof( *m_pePredMode ) ); + memset( m_CUTransquantBypass, false, m_uiNumPartition * sizeof( *m_CUTransquantBypass) ); + memset( m_puhDepth , 0, m_uiNumPartition * sizeof( *m_puhDepth ) ); + memset( m_puhTrIdx , 0, m_uiNumPartition * sizeof( *m_puhTrIdx ) ); + memset( m_puhWidth , g_uiMaxCUWidth, m_uiNumPartition * sizeof( *m_puhWidth ) ); + memset( m_puhHeight , g_uiMaxCUHeight, m_uiNumPartition * sizeof( *m_puhHeight ) ); + for(UInt i=0; igetSliceQp(), m_uiNumPartition * sizeof( *m_phQP ) ); + memset( m_ChromaQpAdj , 0, m_uiNumPartition * sizeof( *m_ChromaQpAdj ) ); + for(UInt comp=0; compgetComponentScaleX(ComponentID(comp)) + m_pcPic->getComponentScaleY(ComponentID(comp)); + memset( m_pcTrCoeff[comp], 0, sizeof(TCoeff)* numCoeffY>>componentShift ); +#if ADAPTIVE_QP_SELECTION + memset( m_pcArlCoeff[comp], 0, sizeof(TCoeff)* numCoeffY>>componentShift ); +#endif + } + + for(UInt i=0; igetFrameWidthInCtus(); + if ( m_ctuRsAddr % frameWidthInCtus ) + { + m_pCtuLeft = pcPic->getCtu( m_ctuRsAddr - 1 ); + } + + if ( m_ctuRsAddr / frameWidthInCtus ) + { + m_pCtuAbove = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus ); + } + + if ( m_pCtuLeft && m_pCtuAbove ) + { + m_pCtuAboveLeft = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus - 1 ); + } + + if ( m_pCtuAbove && ( (m_ctuRsAddr%frameWidthInCtus) < (frameWidthInCtus-1) ) ) + { + m_pCtuAboveRight = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus + 1 ); + } + + for(UInt i=0; igetNumRefIdx( rpl ) > 0 ) + { + m_apcCUColocated[rpl] = getSlice()->getRefPic( rpl, 0)->getCtu( m_ctuRsAddr ); + } + } +} + + +/** initialize prediction data with enabling sub-CTU-level delta QP +*\param uiDepth depth of the current CU +*\param qp qp for the current CU +*- set CU width and CU height according to depth +*- set qp value according to input qp +*- set last-coded qp value according to input last-coded qp +*/ +Void TComDataCU::initEstData( const UInt uiDepth, const Int qp, const Bool bTransquantBypass ) +{ + m_dTotalCost = MAX_DOUBLE; + m_uiTotalDistortion = 0; + m_uiTotalBits = 0; + m_uiTotalBins = 0; + + UChar uhWidth = g_uiMaxCUWidth >> uiDepth; + UChar uhHeight = g_uiMaxCUHeight >> uiDepth; + + for (UInt ui = 0; ui < m_uiNumPartition; ui++) + { + for(UInt i=0; i> (getPic()->getComponentScaleX(component) + getPic()->getComponentScaleY(component)); + memset( m_pcTrCoeff[comp], 0, numCoeff * sizeof( TCoeff ) ); +#if ADAPTIVE_QP_SELECTION + memset( m_pcArlCoeff[comp], 0, numCoeff * sizeof( TCoeff ) ); +#endif + memset( m_pcIPCMSample[comp], 0, numCoeff * sizeof( Pel) ); + } +} + + +// initialize Sub partition +Void TComDataCU::initSubCU( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth, Int qp ) +{ + assert( uiPartUnitIdx<4 ); + + UInt uiPartOffset = ( pcCU->getTotalNumPart()>>2 )*uiPartUnitIdx; + + m_pcPic = pcCU->getPic(); + m_pcSlice = m_pcPic->getSlice(m_pcPic->getCurrSliceIdx()); + m_ctuRsAddr = pcCU->getCtuRsAddr(); + m_absZIdxInCtu = pcCU->getZorderIdxInCtu() + uiPartOffset; + + m_uiCUPelX = pcCU->getCUPelX() + ( g_uiMaxCUWidth>>uiDepth )*( uiPartUnitIdx & 1 ); + m_uiCUPelY = pcCU->getCUPelY() + ( g_uiMaxCUHeight>>uiDepth )*( uiPartUnitIdx >> 1 ); + + m_dTotalCost = MAX_DOUBLE; + m_uiTotalDistortion = 0; + m_uiTotalBits = 0; + m_uiTotalBins = 0; + m_uiNumPartition = pcCU->getTotalNumPart() >> 2; + + Int iSizeInUchar = sizeof( UChar ) * m_uiNumPartition; + Int iSizeInBool = sizeof( Bool ) * m_uiNumPartition; + Int sizeInChar = sizeof( Char ) * m_uiNumPartition; + + memset( m_phQP, qp, sizeInChar ); + memset( m_pbMergeFlag, 0, iSizeInBool ); + memset( m_puhMergeIndex, 0, iSizeInUchar ); + for (UInt ch=0; ch> uiDepth; + UChar uhHeight = g_uiMaxCUHeight >> uiDepth; + memset( m_puhWidth, uhWidth, iSizeInUchar ); + memset( m_puhHeight, uhHeight, iSizeInUchar ); + memset( m_pbIPCMFlag, 0, iSizeInBool ); + for (UInt ui = 0; ui < m_uiNumPartition; ui++) + { + m_skipFlag[ui] = false; + m_pePartSize[ui] = NUMBER_OF_PART_SIZES; + m_pePredMode[ui] = NUMBER_OF_PREDICTION_MODES; + m_CUTransquantBypass[ui] = false; + m_ChromaQpAdj[ui] = 0; + + for(UInt i=0; igetComponentScaleX(ComponentID(ch)) + m_pcPic->getComponentScaleY(ComponentID(ch)); + memset( m_pcTrCoeff[ch], 0, sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#if ADAPTIVE_QP_SELECTION + memset( m_pcArlCoeff[ch], 0, sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#endif + memset( m_pcIPCMSample[ch], 0, sizeof(Pel)* (numCoeffY>>componentShift) ); + } + + for(UInt i=0; igetCtuLeft(); + m_pCtuAbove = pcCU->getCtuAbove(); + m_pCtuAboveLeft = pcCU->getCtuAboveLeft(); + m_pCtuAboveRight = pcCU->getCtuAboveRight(); + + for(UInt i=0; igetCUColocated(RefPicList(i)); + } +} + +Void TComDataCU::setOutsideCUPart( UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiNumPartition = m_uiNumPartition >> (uiDepth << 1); + UInt uiSizeInUchar = sizeof( UChar ) * uiNumPartition; + + UChar uhWidth = g_uiMaxCUWidth >> uiDepth; + UChar uhHeight = g_uiMaxCUHeight >> uiDepth; + memset( m_puhDepth + uiAbsPartIdx, uiDepth, uiSizeInUchar ); + memset( m_puhWidth + uiAbsPartIdx, uhWidth, uiSizeInUchar ); + memset( m_puhHeight + uiAbsPartIdx, uhHeight, uiSizeInUchar ); +} + +// -------------------------------------------------------------------------------------------------------------------- +// Copy +// -------------------------------------------------------------------------------------------------------------------- + +Void TComDataCU::copySubCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiPart = uiAbsPartIdx; + + m_pcPic = pcCU->getPic(); + m_pcSlice = pcCU->getSlice(); + m_ctuRsAddr = pcCU->getCtuRsAddr(); + m_absZIdxInCtu = uiAbsPartIdx; + + m_uiCUPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ]; + m_uiCUPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ]; + + m_skipFlag=pcCU->getSkipFlag() + uiPart; + + m_phQP=pcCU->getQP() + uiPart; + m_ChromaQpAdj = pcCU->getChromaQpAdj() + uiPart; + m_pePartSize = pcCU->getPartitionSize() + uiPart; + m_pePredMode=pcCU->getPredictionMode() + uiPart; + m_CUTransquantBypass = pcCU->getCUTransquantBypass()+uiPart; + + m_pbMergeFlag = pcCU->getMergeFlag() + uiPart; + m_puhMergeIndex = pcCU->getMergeIndex() + uiPart; + + for (UInt ch=0; chgetIntraDir(ChannelType(ch)) + uiPart; + } + + m_puhInterDir = pcCU->getInterDir() + uiPart; + m_puhTrIdx = pcCU->getTransformIdx() + uiPart; + + for(UInt comp=0; compgetCrossComponentPredictionAlpha(ComponentID(comp)) + uiPart; + m_puhTransformSkip[comp] = pcCU->getTransformSkip(ComponentID(comp)) + uiPart; + m_puhCbf[comp] = pcCU->getCbf(ComponentID(comp)) + uiPart; + m_explicitRdpcmMode[comp] = pcCU->getExplicitRdpcmMode(ComponentID(comp)) + uiPart; + } + + m_puhDepth=pcCU->getDepth() + uiPart; + m_puhWidth=pcCU->getWidth() + uiPart; + m_puhHeight=pcCU->getHeight() + uiPart; + + m_pbIPCMFlag = pcCU->getIPCMFlag() + uiPart; + + m_pCtuAboveLeft = pcCU->getCtuAboveLeft(); + m_pCtuAboveRight = pcCU->getCtuAboveRight(); + m_pCtuAbove = pcCU->getCtuAbove(); + m_pCtuLeft = pcCU->getCtuLeft(); + + for(UInt i=0; igetCUColocated(rpl); + m_apiMVPIdx[rpl]=pcCU->getMVPIdx(rpl) + uiPart; + m_apiMVPNum[rpl]=pcCU->getMVPNum(rpl) + uiPart; + } + + for(UInt i=0; igetCUMvField(rpl), uiPart ); + } + + UInt uiMaxCuWidth=pcCU->getSlice()->getSPS()->getMaxCUWidth(); + UInt uiMaxCuHeight=pcCU->getSlice()->getSPS()->getMaxCUHeight(); + + UInt uiCoffOffset = uiMaxCuWidth*uiMaxCuHeight*uiAbsPartIdx/pcCU->getPic()->getNumPartitionsInCtu(); + + for (UInt ch=0; chgetComponentScaleX(component) + m_pcPic->getComponentScaleY(component); + const UInt offset = uiCoffOffset >> componentShift; + m_pcTrCoeff[ch] = pcCU->getCoeff(component) + offset; +#if ADAPTIVE_QP_SELECTION + m_pcArlCoeff[ch] = pcCU->getArlCoeff(component) + offset; +#endif + m_pcIPCMSample[ch] = pcCU->getPCMSample(component) + offset; + } +} + +// Copy inter prediction info from the biggest CU +Void TComDataCU::copyInterPredInfoFrom ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList ) +{ + m_pcPic = pcCU->getPic(); + m_pcSlice = pcCU->getSlice(); + m_ctuRsAddr = pcCU->getCtuRsAddr(); + m_absZIdxInCtu = uiAbsPartIdx; + + Int iRastPartIdx = g_auiZscanToRaster[uiAbsPartIdx]; + m_uiCUPelX = pcCU->getCUPelX() + m_pcPic->getMinCUWidth ()*( iRastPartIdx % m_pcPic->getNumPartInCtuWidth() ); + m_uiCUPelY = pcCU->getCUPelY() + m_pcPic->getMinCUHeight()*( iRastPartIdx / m_pcPic->getNumPartInCtuWidth() ); + + m_pCtuAboveLeft = pcCU->getCtuAboveLeft(); + m_pCtuAboveRight = pcCU->getCtuAboveRight(); + m_pCtuAbove = pcCU->getCtuAbove(); + m_pCtuLeft = pcCU->getCtuLeft(); + + for(UInt i=0; igetCUColocated(RefPicList(i)); + } + + m_skipFlag = pcCU->getSkipFlag () + uiAbsPartIdx; + + m_pePartSize = pcCU->getPartitionSize () + uiAbsPartIdx; + m_pePredMode = pcCU->getPredictionMode() + uiAbsPartIdx; + m_ChromaQpAdj = pcCU->getChromaQpAdj() + uiAbsPartIdx; + m_CUTransquantBypass = pcCU->getCUTransquantBypass() + uiAbsPartIdx; + m_puhInterDir = pcCU->getInterDir () + uiAbsPartIdx; + + m_puhDepth = pcCU->getDepth () + uiAbsPartIdx; + m_puhWidth = pcCU->getWidth () + uiAbsPartIdx; + m_puhHeight = pcCU->getHeight() + uiAbsPartIdx; + + m_pbMergeFlag = pcCU->getMergeFlag() + uiAbsPartIdx; + m_puhMergeIndex = pcCU->getMergeIndex() + uiAbsPartIdx; + + m_apiMVPIdx[eRefPicList] = pcCU->getMVPIdx(eRefPicList) + uiAbsPartIdx; + m_apiMVPNum[eRefPicList] = pcCU->getMVPNum(eRefPicList) + uiAbsPartIdx; + + m_acCUMvField[ eRefPicList ].linkToWithOffset( pcCU->getCUMvField(eRefPicList), uiAbsPartIdx ); +} + +// Copy small CU to bigger CU. +// One of quarter parts overwritten by predicted sub part. +Void TComDataCU::copyPartFrom( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth ) +{ + assert( uiPartUnitIdx<4 ); + + m_dTotalCost += pcCU->getTotalCost(); + m_uiTotalDistortion += pcCU->getTotalDistortion(); + m_uiTotalBits += pcCU->getTotalBits(); + + UInt uiOffset = pcCU->getTotalNumPart()*uiPartUnitIdx; + const UInt numValidComp=pcCU->getPic()->getNumberValidComponents(); + const UInt numValidChan=pcCU->getPic()->getChromaFormat()==CHROMA_400 ? 1:2; + + UInt uiNumPartition = pcCU->getTotalNumPart(); + Int iSizeInUchar = sizeof( UChar ) * uiNumPartition; + Int iSizeInBool = sizeof( Bool ) * uiNumPartition; + + Int sizeInChar = sizeof( Char ) * uiNumPartition; + memcpy( m_skipFlag + uiOffset, pcCU->getSkipFlag(), sizeof( *m_skipFlag ) * uiNumPartition ); + memcpy( m_phQP + uiOffset, pcCU->getQP(), sizeInChar ); + memcpy( m_pePartSize + uiOffset, pcCU->getPartitionSize(), sizeof( *m_pePartSize ) * uiNumPartition ); + memcpy( m_pePredMode + uiOffset, pcCU->getPredictionMode(), sizeof( *m_pePredMode ) * uiNumPartition ); + memcpy( m_ChromaQpAdj + uiOffset, pcCU->getChromaQpAdj(), sizeof( *m_ChromaQpAdj ) * uiNumPartition ); + memcpy( m_CUTransquantBypass + uiOffset, pcCU->getCUTransquantBypass(), sizeof( *m_CUTransquantBypass ) * uiNumPartition ); + memcpy( m_pbMergeFlag + uiOffset, pcCU->getMergeFlag(), iSizeInBool ); + memcpy( m_puhMergeIndex + uiOffset, pcCU->getMergeIndex(), iSizeInUchar ); + + for (UInt ch=0; chgetIntraDir(ChannelType(ch)), iSizeInUchar ); + } + + memcpy( m_puhInterDir + uiOffset, pcCU->getInterDir(), iSizeInUchar ); + memcpy( m_puhTrIdx + uiOffset, pcCU->getTransformIdx(), iSizeInUchar ); + + for(UInt comp=0; compgetCrossComponentPredictionAlpha(ComponentID(comp)), iSizeInUchar ); + memcpy( m_puhTransformSkip[comp] + uiOffset, pcCU->getTransformSkip(ComponentID(comp)) , iSizeInUchar ); + memcpy( m_puhCbf[comp] + uiOffset, pcCU->getCbf(ComponentID(comp)) , iSizeInUchar ); + memcpy( m_explicitRdpcmMode[comp] + uiOffset, pcCU->getExplicitRdpcmMode(ComponentID(comp)) , iSizeInUchar ); + } + + memcpy( m_puhDepth + uiOffset, pcCU->getDepth(), iSizeInUchar ); + memcpy( m_puhWidth + uiOffset, pcCU->getWidth(), iSizeInUchar ); + memcpy( m_puhHeight + uiOffset, pcCU->getHeight(), iSizeInUchar ); + + memcpy( m_pbIPCMFlag + uiOffset, pcCU->getIPCMFlag(), iSizeInBool ); + + m_pCtuAboveLeft = pcCU->getCtuAboveLeft(); + m_pCtuAboveRight = pcCU->getCtuAboveRight(); + m_pCtuAbove = pcCU->getCtuAbove(); + m_pCtuLeft = pcCU->getCtuLeft(); + + for(UInt i=0; igetMVPIdx(rpl), iSizeInUchar ); + memcpy( m_apiMVPNum[rpl] + uiOffset, pcCU->getMVPNum(rpl), iSizeInUchar ); + m_apcCUColocated[rpl] = pcCU->getCUColocated(rpl); + } + + for(UInt i=0; igetCUMvField( rpl ), pcCU->getTotalNumPart(), uiOffset ); + } + + const UInt numCoeffY = g_uiMaxCUWidth*g_uiMaxCUHeight >> (uiDepth<<1); + const UInt offsetY = uiPartUnitIdx*numCoeffY; + for (UInt ch=0; chgetComponentScaleX(component) + m_pcPic->getComponentScaleY(component); + const UInt offset = offsetY>>componentShift; + memcpy( m_pcTrCoeff [ch] + offset, pcCU->getCoeff(component), sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#if ADAPTIVE_QP_SELECTION + memcpy( m_pcArlCoeff[ch] + offset, pcCU->getArlCoeff(component), sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#endif + memcpy( m_pcIPCMSample[ch] + offset, pcCU->getPCMSample(component), sizeof(Pel)*(numCoeffY>>componentShift) ); + } + + m_uiTotalBins += pcCU->getTotalBins(); +} + +// Copy current predicted part to a CU in picture. +// It is used to predict for next part +Void TComDataCU::copyToPic( UChar uhDepth ) +{ + TComDataCU* pCtu = m_pcPic->getCtu( m_ctuRsAddr ); + const UInt numValidComp=pCtu->getPic()->getNumberValidComponents(); + const UInt numValidChan=pCtu->getPic()->getChromaFormat()==CHROMA_400 ? 1:2; + + pCtu->getTotalCost() = m_dTotalCost; + pCtu->getTotalDistortion() = m_uiTotalDistortion; + pCtu->getTotalBits() = m_uiTotalBits; + + Int iSizeInUchar = sizeof( UChar ) * m_uiNumPartition; + Int iSizeInBool = sizeof( Bool ) * m_uiNumPartition; + Int sizeInChar = sizeof( Char ) * m_uiNumPartition; + + memcpy( pCtu->getSkipFlag() + m_absZIdxInCtu, m_skipFlag, sizeof( *m_skipFlag ) * m_uiNumPartition ); + + memcpy( pCtu->getQP() + m_absZIdxInCtu, m_phQP, sizeInChar ); + + memcpy( pCtu->getPartitionSize() + m_absZIdxInCtu, m_pePartSize, sizeof( *m_pePartSize ) * m_uiNumPartition ); + memcpy( pCtu->getPredictionMode() + m_absZIdxInCtu, m_pePredMode, sizeof( *m_pePredMode ) * m_uiNumPartition ); + memcpy( pCtu->getChromaQpAdj() + m_absZIdxInCtu, m_ChromaQpAdj, sizeof( *m_ChromaQpAdj ) * m_uiNumPartition ); + memcpy( pCtu->getCUTransquantBypass()+ m_absZIdxInCtu, m_CUTransquantBypass, sizeof( *m_CUTransquantBypass ) * m_uiNumPartition ); + memcpy( pCtu->getMergeFlag() + m_absZIdxInCtu, m_pbMergeFlag, iSizeInBool ); + memcpy( pCtu->getMergeIndex() + m_absZIdxInCtu, m_puhMergeIndex, iSizeInUchar ); + for (UInt ch=0; chgetIntraDir(ChannelType(ch)) + m_absZIdxInCtu, m_puhIntraDir[ch], iSizeInUchar); + } + + memcpy( pCtu->getInterDir() + m_absZIdxInCtu, m_puhInterDir, iSizeInUchar ); + memcpy( pCtu->getTransformIdx() + m_absZIdxInCtu, m_puhTrIdx, iSizeInUchar ); + + for(UInt comp=0; compgetCrossComponentPredictionAlpha(ComponentID(comp)) + m_absZIdxInCtu, m_crossComponentPredictionAlpha[comp], iSizeInUchar ); + memcpy( pCtu->getTransformSkip(ComponentID(comp)) + m_absZIdxInCtu, m_puhTransformSkip[comp], iSizeInUchar ); + memcpy( pCtu->getCbf(ComponentID(comp)) + m_absZIdxInCtu, m_puhCbf[comp], iSizeInUchar ); + memcpy( pCtu->getExplicitRdpcmMode(ComponentID(comp)) + m_absZIdxInCtu, m_explicitRdpcmMode[comp], iSizeInUchar ); + } + + memcpy( pCtu->getDepth() + m_absZIdxInCtu, m_puhDepth, iSizeInUchar ); + memcpy( pCtu->getWidth() + m_absZIdxInCtu, m_puhWidth, iSizeInUchar ); + memcpy( pCtu->getHeight() + m_absZIdxInCtu, m_puhHeight, iSizeInUchar ); + + for(UInt i=0; igetMVPIdx(rpl) + m_absZIdxInCtu, m_apiMVPIdx[rpl], iSizeInUchar ); + memcpy( pCtu->getMVPNum(rpl) + m_absZIdxInCtu, m_apiMVPNum[rpl], iSizeInUchar ); + } + + for(UInt i=0; igetCUMvField( rpl ), m_absZIdxInCtu ); + } + + memcpy( pCtu->getIPCMFlag() + m_absZIdxInCtu, m_pbIPCMFlag, iSizeInBool ); + + const UInt numCoeffY = (g_uiMaxCUWidth*g_uiMaxCUHeight)>>(uhDepth<<1); + const UInt offsetY = m_absZIdxInCtu*m_pcPic->getMinCUWidth()*m_pcPic->getMinCUHeight(); + for (UInt comp=0; compgetComponentScaleX(component) + m_pcPic->getComponentScaleY(component); + memcpy( pCtu->getCoeff(component) + (offsetY>>componentShift), m_pcTrCoeff[component], sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#if ADAPTIVE_QP_SELECTION + memcpy( pCtu->getArlCoeff(component) + (offsetY>>componentShift), m_pcArlCoeff[component], sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#endif + memcpy( pCtu->getPCMSample(component) + (offsetY>>componentShift), m_pcIPCMSample[component], sizeof(Pel)*(numCoeffY>>componentShift) ); + } + + pCtu->getTotalBins() = m_uiTotalBins; +} + +Void TComDataCU::copyToPic( UChar uhDepth, UInt uiPartIdx, UInt uiPartDepth ) +{ + TComDataCU* pCtu = m_pcPic->getCtu( m_ctuRsAddr ); + UInt uiQNumPart = m_uiNumPartition>>(uiPartDepth<<1); + + UInt uiPartStart = uiPartIdx*uiQNumPart; + UInt uiPartOffset = m_absZIdxInCtu + uiPartStart; + + const UInt numValidComp=pCtu->getPic()->getNumberValidComponents(); + const UInt numValidChan=pCtu->getPic()->getChromaFormat()==CHROMA_400 ? 1:2; + + pCtu->getTotalCost() = m_dTotalCost; + pCtu->getTotalDistortion() = m_uiTotalDistortion; + pCtu->getTotalBits() = m_uiTotalBits; + + Int iSizeInUchar = sizeof( UChar ) * uiQNumPart; + Int iSizeInBool = sizeof( Bool ) * uiQNumPart; + Int sizeInChar = sizeof( Char ) * uiQNumPart; + + memcpy( pCtu->getSkipFlag() + uiPartOffset, m_skipFlag, sizeof( *m_skipFlag ) * uiQNumPart ); + + memcpy( pCtu->getQP() + uiPartOffset, m_phQP, sizeInChar ); + memcpy( pCtu->getPartitionSize() + uiPartOffset, m_pePartSize, sizeof( *m_pePartSize ) * uiQNumPart ); + memcpy( pCtu->getPredictionMode() + uiPartOffset, m_pePredMode, sizeof( *m_pePredMode ) * uiQNumPart ); + + memcpy( pCtu->getCUTransquantBypass()+ uiPartOffset, m_CUTransquantBypass, sizeof( *m_CUTransquantBypass ) * uiQNumPart ); + memcpy( pCtu->getMergeFlag() + uiPartOffset, m_pbMergeFlag, iSizeInBool ); + memcpy( pCtu->getMergeIndex() + uiPartOffset, m_puhMergeIndex, iSizeInUchar ); + for (UInt ch=0; chgetIntraDir(ChannelType(ch)) + uiPartOffset, m_puhIntraDir[ch], iSizeInUchar ); + } + + memcpy( pCtu->getInterDir() + uiPartOffset, m_puhInterDir, iSizeInUchar ); + memcpy( pCtu->getTransformIdx() + uiPartOffset, m_puhTrIdx, iSizeInUchar ); + + for(UInt comp=0; compgetCrossComponentPredictionAlpha(ComponentID(comp)) + uiPartOffset, m_crossComponentPredictionAlpha[comp], iSizeInUchar ); + memcpy( pCtu->getTransformSkip(ComponentID(comp) ) + uiPartOffset, m_puhTransformSkip[comp], iSizeInUchar ); + memcpy( pCtu->getCbf(ComponentID(comp)) + uiPartOffset, m_puhCbf[comp], iSizeInUchar ); + memcpy( pCtu->getExplicitRdpcmMode(ComponentID(comp) ) + uiPartOffset, m_explicitRdpcmMode[comp], iSizeInUchar ); + } + + memcpy( pCtu->getDepth() + uiPartOffset, m_puhDepth, iSizeInUchar ); + memcpy( pCtu->getWidth() + uiPartOffset, m_puhWidth, iSizeInUchar ); + memcpy( pCtu->getHeight() + uiPartOffset, m_puhHeight, iSizeInUchar ); + + for(UInt i=0; igetMVPIdx(rpl) + uiPartOffset, m_apiMVPIdx[rpl], iSizeInUchar ); + memcpy( pCtu->getMVPNum(rpl) + uiPartOffset, m_apiMVPNum[rpl], iSizeInUchar ); + } + + for(UInt i=0; igetCUMvField( rpl ), m_absZIdxInCtu, uiPartStart, uiQNumPart ); + } + + memcpy( pCtu->getIPCMFlag() + uiPartOffset, m_pbIPCMFlag, iSizeInBool ); + + const UInt numCoeffY = (g_uiMaxCUWidth*g_uiMaxCUHeight)>>((uhDepth+uiPartDepth)<<1); + const UInt offsetY = uiPartOffset*m_pcPic->getMinCUWidth()*m_pcPic->getMinCUHeight(); + for (UInt comp=0; compgetComponentScaleX(ComponentID(comp)) + m_pcPic->getComponentScaleY(ComponentID(comp)); + memcpy( pCtu->getCoeff(ComponentID(comp)) + (offsetY>>componentShift), m_pcTrCoeff[comp], sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#if ADAPTIVE_QP_SELECTION + memcpy( pCtu->getArlCoeff(ComponentID(comp)) + (offsetY>>componentShift), m_pcArlCoeff[comp], sizeof(TCoeff)*(numCoeffY>>componentShift) ); +#endif + memcpy( pCtu->getPCMSample(ComponentID(comp)) + (offsetY>>componentShift), m_pcIPCMSample[comp], sizeof(Pel)*(numCoeffY>>componentShift) ); + } + + pCtu->getTotalBins() = m_uiTotalBins; +} + +// -------------------------------------------------------------------------------------------------------------------- +// Other public functions +// -------------------------------------------------------------------------------------------------------------------- + +TComDataCU* TComDataCU::getPULeft( UInt& uiLPartUnitIdx, + UInt uiCurrPartUnitIdx, + Bool bEnforceSliceRestriction, + Bool bEnforceTileRestriction ) +{ + UInt uiAbsPartIdx = g_auiZscanToRaster[uiCurrPartUnitIdx]; + UInt uiAbsZorderCUIdx = g_auiZscanToRaster[m_absZIdxInCtu]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + + if ( !RasterAddress::isZeroCol( uiAbsPartIdx, numPartInCtuWidth ) ) + { + uiLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - 1 ]; + if ( RasterAddress::isEqualCol( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiLPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + + uiLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + numPartInCtuWidth - 1 ]; + if ( (bEnforceSliceRestriction && !CUIsFromSameSlice(m_pCtuLeft)) || (bEnforceTileRestriction && !CUIsFromSameTile(m_pCtuLeft)) ) + { + return NULL; + } + return m_pCtuLeft; +} + + +TComDataCU* TComDataCU::getPUAbove( UInt& uiAPartUnitIdx, + UInt uiCurrPartUnitIdx, + Bool bEnforceSliceRestriction, + Bool planarAtCtuBoundary, + Bool bEnforceTileRestriction ) +{ + UInt uiAbsPartIdx = g_auiZscanToRaster[uiCurrPartUnitIdx]; + UInt uiAbsZorderCUIdx = g_auiZscanToRaster[m_absZIdxInCtu]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + + if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) ) + { + uiAPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - numPartInCtuWidth ]; + if ( RasterAddress::isEqualRow( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiAPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + + if(planarAtCtuBoundary) + { + return NULL; + } + + uiAPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth ]; + + if ( (bEnforceSliceRestriction && !CUIsFromSameSlice(m_pCtuAbove)) || (bEnforceTileRestriction && !CUIsFromSameTile(m_pCtuAbove)) ) + { + return NULL; + } + return m_pCtuAbove; +} + +TComDataCU* TComDataCU::getPUAboveLeft( UInt& uiALPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction ) +{ + UInt uiAbsPartIdx = g_auiZscanToRaster[uiCurrPartUnitIdx]; + UInt uiAbsZorderCUIdx = g_auiZscanToRaster[m_absZIdxInCtu]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + + if ( !RasterAddress::isZeroCol( uiAbsPartIdx, numPartInCtuWidth ) ) + { + if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) ) + { + uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - numPartInCtuWidth - 1 ]; + if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiALPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + getPic()->getNumPartitionsInCtu() - numPartInCtuWidth - 1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) ) + { + return NULL; + } + return m_pCtuAbove; + } + + if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) ) + { + uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - 1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) ) + { + return NULL; + } + return m_pCtuLeft; + } + + uiALPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - 1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveLeft) ) + { + return NULL; + } + return m_pCtuAboveLeft; +} + +TComDataCU* TComDataCU::getPUAboveRight( UInt& uiARPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction ) +{ + UInt uiAbsPartIdxRT = g_auiZscanToRaster[uiCurrPartUnitIdx]; + UInt uiAbsZorderCUIdx = g_auiZscanToRaster[ m_absZIdxInCtu ] + m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + + if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxRT] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() ) + { + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + + if ( RasterAddress::lessThanCol( uiAbsPartIdxRT, numPartInCtuWidth - 1, numPartInCtuWidth ) ) + { + if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) ) + { + if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + 1 ] ) + { + uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + 1 ]; + if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxRT, uiAbsZorderCUIdx, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiARPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + 1 ]; + + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) ) + { + return NULL; + } + return m_pCtuAbove; + } + + if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) ) + { + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + + uiARPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth ]; + + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveRight) ) + { + return NULL; + } + return m_pCtuAboveRight; +} + +TComDataCU* TComDataCU::getPUBelowLeft( UInt& uiBLPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction ) +{ + UInt uiAbsPartIdxLB = g_auiZscanToRaster[uiCurrPartUnitIdx]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + UInt uiAbsZorderCUIdxLB = g_auiZscanToRaster[ m_absZIdxInCtu ] + (m_puhHeight[0] / m_pcPic->getMinCUHeight() - 1)*numPartInCtuWidth; + + if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxLB] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) + { + uiBLPartUnitIdx = MAX_UINT; + return NULL; + } + + if ( RasterAddress::lessThanRow( uiAbsPartIdxLB, m_pcPic->getNumPartInCtuHeight() - 1, numPartInCtuWidth ) ) + { + if ( !RasterAddress::isZeroCol( uiAbsPartIdxLB, numPartInCtuWidth ) ) + { + if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth - 1 ] ) + { + uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth - 1 ]; + if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxLB, uiAbsZorderCUIdxLB, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiBLPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + uiBLPartUnitIdx = MAX_UINT; + return NULL; + } + uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth*2 - 1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) ) + { + return NULL; + } + return m_pCtuLeft; + } + + uiBLPartUnitIdx = MAX_UINT; + return NULL; +} + +TComDataCU* TComDataCU::getPUBelowLeftAdi(UInt& uiBLPartUnitIdx, UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset, Bool bEnforceSliceRestriction) +{ + UInt uiAbsPartIdxLB = g_auiZscanToRaster[uiCurrPartUnitIdx]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + UInt uiAbsZorderCUIdxLB = g_auiZscanToRaster[ m_absZIdxInCtu ] + ((m_puhHeight[0] / m_pcPic->getMinCUHeight()) - 1)*numPartInCtuWidth; + + if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxLB] + (m_pcPic->getPicSym()->getMinCUHeight() * uiPartUnitOffset)) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples()) + { + uiBLPartUnitIdx = MAX_UINT; + return NULL; + } + + if ( RasterAddress::lessThanRow( uiAbsPartIdxLB, m_pcPic->getNumPartInCtuHeight() - uiPartUnitOffset, numPartInCtuWidth ) ) + { + if ( !RasterAddress::isZeroCol( uiAbsPartIdxLB, numPartInCtuWidth ) ) + { + if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxLB + uiPartUnitOffset * numPartInCtuWidth - 1 ] ) + { + uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + uiPartUnitOffset * numPartInCtuWidth - 1 ]; + if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxLB, uiAbsZorderCUIdxLB, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiBLPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + uiBLPartUnitIdx = MAX_UINT; + return NULL; + } + uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + (1+uiPartUnitOffset) * numPartInCtuWidth - 1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) ) + { + return NULL; + } + return m_pCtuLeft; + } + + uiBLPartUnitIdx = MAX_UINT; + return NULL; +} + +TComDataCU* TComDataCU::getPUAboveRightAdi(UInt& uiARPartUnitIdx, UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset, Bool bEnforceSliceRestriction) +{ + UInt uiAbsPartIdxRT = g_auiZscanToRaster[uiCurrPartUnitIdx]; + UInt uiAbsZorderCUIdx = g_auiZscanToRaster[ m_absZIdxInCtu ] + (m_puhWidth[0] / m_pcPic->getMinCUWidth()) - 1; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + + if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxRT] + (m_pcPic->getPicSym()->getMinCUHeight() * uiPartUnitOffset)) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() ) + { + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + + if ( RasterAddress::lessThanCol( uiAbsPartIdxRT, numPartInCtuWidth - uiPartUnitOffset, numPartInCtuWidth ) ) + { + if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) ) + { + if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + uiPartUnitOffset ] ) + { + uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + uiPartUnitOffset ]; + if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxRT, uiAbsZorderCUIdx, numPartInCtuWidth ) ) + { + return m_pcPic->getCtu( getCtuRsAddr() ); + } + else + { + uiARPartUnitIdx -= m_absZIdxInCtu; + return this; + } + } + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + + uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + uiPartUnitOffset ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) ) + { + return NULL; + } + return m_pCtuAbove; + } + + if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) ) + { + uiARPartUnitIdx = MAX_UINT; + return NULL; + } + + uiARPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + uiPartUnitOffset-1 ]; + if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveRight) ) + { + return NULL; + } + return m_pCtuAboveRight; +} + +/** Get left QpMinCu +*\param uiLPartUnitIdx +*\param uiCurrAbsIdxInCtu +*\returns TComDataCU* point of TComDataCU of left QpMinCu +*/ +TComDataCU* TComDataCU::getQpMinCuLeft( UInt& uiLPartUnitIdx, UInt uiCurrAbsIdxInCtu ) +{ + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + UInt absZorderQpMinCUIdx = (uiCurrAbsIdxInCtu>>((g_uiMaxCUDepth - getSlice()->getPPS()->getMaxCuDQPDepth())<<1))<<((g_uiMaxCUDepth -getSlice()->getPPS()->getMaxCuDQPDepth())<<1); + UInt absRorderQpMinCUIdx = g_auiZscanToRaster[absZorderQpMinCUIdx]; + + // check for left CTU boundary + if ( RasterAddress::isZeroCol(absRorderQpMinCUIdx, numPartInCtuWidth) ) + { + return NULL; + } + + // get index of left-CU relative to top-left corner of current quantization group + uiLPartUnitIdx = g_auiRasterToZscan[absRorderQpMinCUIdx - 1]; + + // return pointer to current CTU + return m_pcPic->getCtu( getCtuRsAddr() ); +} + +/** Get Above QpMinCu +*\param uiAPartUnitIdx +*\param uiCurrAbsIdxInCtu +*\returns TComDataCU* point of TComDataCU of above QpMinCu +*/ +TComDataCU* TComDataCU::getQpMinCuAbove( UInt& uiAPartUnitIdx, UInt uiCurrAbsIdxInCtu ) +{ + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + UInt absZorderQpMinCUIdx = (uiCurrAbsIdxInCtu>>((g_uiMaxCUDepth - getSlice()->getPPS()->getMaxCuDQPDepth())<<1))<<((g_uiMaxCUDepth - getSlice()->getPPS()->getMaxCuDQPDepth())<<1); + UInt absRorderQpMinCUIdx = g_auiZscanToRaster[absZorderQpMinCUIdx]; + + // check for top CTU boundary + if ( RasterAddress::isZeroRow( absRorderQpMinCUIdx, numPartInCtuWidth) ) + { + return NULL; + } + + // get index of top-CU relative to top-left corner of current quantization group + uiAPartUnitIdx = g_auiRasterToZscan[absRorderQpMinCUIdx - numPartInCtuWidth]; + + // return pointer to current CTU + return m_pcPic->getCtu( getCtuRsAddr() ); +} + + + +/** Get reference QP from left QpMinCu or latest coded QP +*\param uiCurrAbsIdxInCtu +*\returns Char reference QP value +*/ +Char TComDataCU::getRefQP( UInt uiCurrAbsIdxInCtu ) +{ + UInt lPartIdx = MAX_UINT; + UInt aPartIdx = MAX_UINT; + TComDataCU* cULeft = getQpMinCuLeft ( lPartIdx, m_absZIdxInCtu + uiCurrAbsIdxInCtu ); + TComDataCU* cUAbove = getQpMinCuAbove( aPartIdx, m_absZIdxInCtu + uiCurrAbsIdxInCtu ); + return (((cULeft? cULeft->getQP( lPartIdx ): getLastCodedQP( uiCurrAbsIdxInCtu )) + (cUAbove? cUAbove->getQP( aPartIdx ): getLastCodedQP( uiCurrAbsIdxInCtu )) + 1) >> 1); +} + +Int TComDataCU::getLastValidPartIdx( Int iAbsPartIdx ) +{ + Int iLastValidPartIdx = iAbsPartIdx-1; + while ( iLastValidPartIdx >= 0 + && getPredictionMode( iLastValidPartIdx ) == NUMBER_OF_PREDICTION_MODES ) + { + UInt uiDepth = getDepth( iLastValidPartIdx ); + iLastValidPartIdx -= m_uiNumPartition>>(uiDepth<<1); + } + return iLastValidPartIdx; +} + +Char TComDataCU::getLastCodedQP( UInt uiAbsPartIdx ) +{ + UInt uiQUPartIdxMask = ~((1<<((g_uiMaxCUDepth - getSlice()->getPPS()->getMaxCuDQPDepth())<<1))-1); + Int iLastValidPartIdx = getLastValidPartIdx( uiAbsPartIdx&uiQUPartIdxMask ); // A idx will be invalid if it is off the right or bottom edge of the picture. + // If this CU is in the first CTU of the slice and there is no valid part before this one, use slice QP + if ( getPic()->getPicSym()->getCtuTsToRsAddrMap(getSlice()->getSliceCurStartCtuTsAddr()) == getCtuRsAddr() && Int(getZorderIdxInCtu())+iLastValidPartIdx<0) + { + return getSlice()->getSliceQp(); + } + else if ( iLastValidPartIdx >= 0 ) + { + // If there is a valid part within the current Sub-CU, use it + return getQP( iLastValidPartIdx ); + } + else + { + if ( getZorderIdxInCtu() > 0 ) + { + // If this wasn't the first sub-cu within the Ctu, explore the CTU itself. + return getPic()->getCtu( getCtuRsAddr() )->getLastCodedQP( getZorderIdxInCtu() ); // TODO - remove this recursion + } + else if ( getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr()) > 0 + && CUIsFromSameSliceTileAndWavefrontRow(getPic()->getCtu(getPic()->getPicSym()->getCtuTsToRsAddrMap(getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr())-1))) ) + { + // If this isn't the first Ctu (how can it be due to the first 'if'?), and the previous Ctu is from the same tile, examine the previous Ctu. + return getPic()->getCtu( getPic()->getPicSym()->getCtuTsToRsAddrMap(getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr())-1) )->getLastCodedQP( getPic()->getNumPartitionsInCtu() ); // TODO - remove this recursion + } + else + { + // No other options available - use the slice-level QP. + return getSlice()->getSliceQp(); + } + } +} + + +/** Check whether the CU is coded in lossless coding mode + * \param uiAbsPartIdx + * \returns true if the CU is coded in lossless coding mode; false if otherwise + */ +Bool TComDataCU::isLosslessCoded(UInt absPartIdx) +{ + return (getSlice()->getPPS()->getTransquantBypassEnableFlag() && getCUTransquantBypass (absPartIdx)); +} + + +/** Get allowed chroma intra modes +*\param uiAbsPartIdx +*\param uiModeList pointer to chroma intra modes array +*\returns +*- fill uiModeList with chroma intra modes +*/ +Void TComDataCU::getAllowedChromaDir( UInt uiAbsPartIdx, UInt uiModeList[NUM_CHROMA_MODE] ) +{ + uiModeList[0] = PLANAR_IDX; + uiModeList[1] = VER_IDX; + uiModeList[2] = HOR_IDX; + uiModeList[3] = DC_IDX; + uiModeList[4] = DM_CHROMA_IDX; + assert(4getChromaFormat(); + // Get intra direction of left PU + pcCULeft = getPULeft( LeftPartIdx, m_absZIdxInCtu + uiAbsPartIdx ); + + if (isChroma(compID)) LeftPartIdx = getChromasCorrespondingPULumaIdx(LeftPartIdx, chForm); + iLeftIntraDir = pcCULeft ? ( pcCULeft->isIntra( LeftPartIdx ) ? pcCULeft->getIntraDir( chType, LeftPartIdx ) : DC_IDX ) : DC_IDX; + + // Get intra direction of above PU + pcCUAbove = getPUAbove( AbovePartIdx, m_absZIdxInCtu + uiAbsPartIdx, true, true ); + + if (isChroma(compID)) AbovePartIdx = getChromasCorrespondingPULumaIdx(AbovePartIdx, chForm); + iAboveIntraDir = pcCUAbove ? ( pcCUAbove->isIntra( AbovePartIdx ) ? pcCUAbove->getIntraDir( chType, AbovePartIdx ) : DC_IDX ) : DC_IDX; + + if (isChroma(chType)) + { + if (iLeftIntraDir == DM_CHROMA_IDX) iLeftIntraDir = pcCULeft-> getIntraDir( CHANNEL_TYPE_LUMA, LeftPartIdx ); + if (iAboveIntraDir == DM_CHROMA_IDX) iAboveIntraDir = pcCUAbove->getIntraDir( CHANNEL_TYPE_LUMA, AbovePartIdx ); + } + + assert (2 1) // angular modes + { + uiIntraDirPred[0] = iLeftIntraDir; + uiIntraDirPred[1] = ((iLeftIntraDir + 29) % 32) + 2; + uiIntraDirPred[2] = ((iLeftIntraDir - 1 ) % 32) + 2; + } + else //non-angular + { + uiIntraDirPred[0] = PLANAR_IDX; + uiIntraDirPred[1] = DC_IDX; + uiIntraDirPred[2] = VER_IDX; + } + } + else + { + if( piMode ) + { + *piMode = 2; + } + uiIntraDirPred[0] = iLeftIntraDir; + uiIntraDirPred[1] = iAboveIntraDir; + + if (iLeftIntraDir && iAboveIntraDir ) //both modes are non-planar + { + uiIntraDirPred[2] = PLANAR_IDX; + } + else + { + uiIntraDirPred[2] = (iLeftIntraDir+iAboveIntraDir)<2? VER_IDX : DC_IDX; + } + } + for (Int i=0; igetDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0; + + // Get above split flag + pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx ); + uiCtx += ( pcTempCU ) ? ( ( pcTempCU->getDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0; + + return uiCtx; +} + +UInt TComDataCU::getCtxQtCbf( TComTU &rTu, const ChannelType chType ) +{ + const UInt transformDepth = rTu.GetTransformDepthRel(); + + if (isChroma(chType)) + { + return transformDepth; + } + else + { + const UInt uiCtx = ( transformDepth == 0 ? 1 : 0 ); + return uiCtx; + } +} + +UInt TComDataCU::getQuadtreeTULog2MinSizeInCU( UInt absPartIdx ) +{ + UInt log2CbSize = g_aucConvertToBit[getWidth( absPartIdx )] + 2; + PartSize partSize = getPartitionSize( absPartIdx ); + UInt quadtreeTUMaxDepth = isIntra( absPartIdx ) ? m_pcSlice->getSPS()->getQuadtreeTUMaxDepthIntra() : m_pcSlice->getSPS()->getQuadtreeTUMaxDepthInter(); + Int intraSplitFlag = ( isIntra( absPartIdx ) && partSize == SIZE_NxN ) ? 1 : 0; + Int interSplitFlag = ((quadtreeTUMaxDepth == 1) && isInter( absPartIdx ) && (partSize != SIZE_2Nx2N) ); + + UInt log2MinTUSizeInCU = 0; + if (log2CbSize < (m_pcSlice->getSPS()->getQuadtreeTULog2MinSize() + quadtreeTUMaxDepth - 1 + interSplitFlag + intraSplitFlag) ) + { + // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is < QuadtreeTULog2MinSize + log2MinTUSizeInCU = m_pcSlice->getSPS()->getQuadtreeTULog2MinSize(); + } + else + { + // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is still >= QuadtreeTULog2MinSize + log2MinTUSizeInCU = log2CbSize - ( quadtreeTUMaxDepth - 1 + interSplitFlag + intraSplitFlag); // stop when trafoDepth == hierarchy_depth = splitFlag + if ( log2MinTUSizeInCU > m_pcSlice->getSPS()->getQuadtreeTULog2MaxSize()) + { + // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is still > QuadtreeTULog2MaxSize + log2MinTUSizeInCU = m_pcSlice->getSPS()->getQuadtreeTULog2MaxSize(); + } + } + return log2MinTUSizeInCU; +} + +UInt TComDataCU::getCtxSkipFlag( UInt uiAbsPartIdx ) +{ + TComDataCU* pcTempCU; + UInt uiTempPartIdx; + UInt uiCtx = 0; + + // Get BCBP of left PU + pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx ); + uiCtx = ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0; + + // Get BCBP of above PU + pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx ); + uiCtx += ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0; + + return uiCtx; +} + +UInt TComDataCU::getCtxInterDir( UInt uiAbsPartIdx ) +{ + return getDepth( uiAbsPartIdx ); +} + + +UChar TComDataCU::getQtRootCbf( UInt uiIdx ) +{ + const UInt numberValidComponents = getPic()->getNumberValidComponents(); + return getCbf( uiIdx, COMPONENT_Y, 0 ) + || ((numberValidComponents > COMPONENT_Cb) && getCbf( uiIdx, COMPONENT_Cb, 0 )) + || ((numberValidComponents > COMPONENT_Cr) && getCbf( uiIdx, COMPONENT_Cr, 0 )); +} + +Void TComDataCU::setCbfSubParts( const UInt uiCbf[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + for(UInt comp=0; compgetNumPartitionsInCtu() >> (uiDepth << 1); + memset( m_puhCbf[compID] + uiAbsPartIdx, uiCbf, sizeof( UChar ) * uiCurrPartNumb ); +} + +/** Sets a coded block flag for all sub-partitions of a partition + * \param uiCbf The value of the coded block flag to be set + * \param eTType + * \param uiAbsPartIdx + * \param uiPartIdx + * \param uiDepth + * \returns Void + */ +Void TComDataCU::setCbfSubParts ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( uiCbf, m_puhCbf[compID], uiAbsPartIdx, uiDepth, uiPartIdx ); +} + +Void TComDataCU::setCbfPartRange ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ) +{ + memset((m_puhCbf[compID] + uiAbsPartIdx), uiCbf, (sizeof(UChar) * uiCoveredPartIdxes)); +} + +Void TComDataCU::bitwiseOrCbfPartRange( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ) +{ + const UInt stopAbsPartIdx = uiAbsPartIdx + uiCoveredPartIdxes; + + for (UInt subPartIdx = uiAbsPartIdx; subPartIdx < stopAbsPartIdx; subPartIdx++) + { + m_puhCbf[compID][subPartIdx] |= uiCbf; + } +} + +Void TComDataCU::setDepthSubParts( UInt uiDepth, UInt uiAbsPartIdx ) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + memset( m_puhDepth + uiAbsPartIdx, uiDepth, sizeof(UChar)*uiCurrPartNumb ); +} + +Bool TComDataCU::isFirstAbsZorderIdxInDepth (UInt uiAbsPartIdx, UInt uiDepth) +{ + UInt uiPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + return (((m_absZIdxInCtu + uiAbsPartIdx)% uiPartNumb) == 0); +} + +Void TComDataCU::setPartSizeSubParts( PartSize eMode, UInt uiAbsPartIdx, UInt uiDepth ) +{ + assert( sizeof( *m_pePartSize) == 1 ); + memset( m_pePartSize + uiAbsPartIdx, eMode, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) ); +} + +Void TComDataCU::setCUTransquantBypassSubParts( Bool flag, UInt uiAbsPartIdx, UInt uiDepth ) +{ + memset( m_CUTransquantBypass + uiAbsPartIdx, flag, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) ); +} + +Void TComDataCU::setSkipFlagSubParts( Bool skip, UInt absPartIdx, UInt depth ) +{ + assert( sizeof( *m_skipFlag) == 1 ); + memset( m_skipFlag + absPartIdx, skip, m_pcPic->getNumPartitionsInCtu() >> ( 2 * depth ) ); +} + +Void TComDataCU::setPredModeSubParts( PredMode eMode, UInt uiAbsPartIdx, UInt uiDepth ) +{ + assert( sizeof( *m_pePredMode) == 1 ); + memset( m_pePredMode + uiAbsPartIdx, eMode, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) ); +} + +Void TComDataCU::setChromaQpAdjSubParts( UChar val, Int absPartIdx, Int depth ) +{ + assert( sizeof(*m_ChromaQpAdj) == 1 ); + memset( m_ChromaQpAdj + absPartIdx, val, m_pcPic->getNumPartitionsInCtu() >> ( 2 * depth ) ); +} + +Void TComDataCU::setQPSubCUs( Int qp, UInt absPartIdx, UInt depth, Bool &foundNonZeroCbf ) +{ + UInt currPartNumb = m_pcPic->getNumPartitionsInCtu() >> (depth << 1); + UInt currPartNumQ = currPartNumb >> 2; + const UInt numValidComp = m_pcPic->getNumberValidComponents(); + + if(!foundNonZeroCbf) + { + if(getDepth(absPartIdx) > depth) + { + for ( UInt partUnitIdx = 0; partUnitIdx < 4; partUnitIdx++ ) + { + setQPSubCUs( qp, absPartIdx+partUnitIdx*currPartNumQ, depth+1, foundNonZeroCbf ); + } + } + else + { + if(getCbf( absPartIdx, COMPONENT_Y ) || (numValidComp>COMPONENT_Cb && getCbf( absPartIdx, COMPONENT_Cb )) || (numValidComp>COMPONENT_Cr && getCbf( absPartIdx, COMPONENT_Cr) ) ) + { + foundNonZeroCbf = true; + } + else + { + setQPSubParts(qp, absPartIdx, depth); + } + } + } +} + +Void TComDataCU::setQPSubParts( Int qp, UInt uiAbsPartIdx, UInt uiDepth ) +{ + const UInt numPart = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + memset(m_phQP+uiAbsPartIdx, qp, numPart); +} + +Void TComDataCU::setIntraDirSubParts( const ChannelType channelType, const UInt dir, const UInt absPartIdx, const UInt depth ) +{ + UInt numPart = m_pcPic->getNumPartitionsInCtu() >> (depth << 1); + memset( m_puhIntraDir[channelType] + absPartIdx, dir,sizeof(UChar)*numPart ); +} + +template +Void TComDataCU::setSubPart( T uiParameter, T* puhBaseCtu, UInt uiCUAddr, UInt uiCUDepth, UInt uiPUIdx ) +{ + assert( sizeof(T) == 1 ); // Using memset() works only for types of size 1 + + UInt uiCurrPartNumQ = (m_pcPic->getNumPartitionsInCtu() >> (2 * uiCUDepth)) >> 2; + switch ( m_pePartSize[ uiCUAddr ] ) + { + case SIZE_2Nx2N: + memset( puhBaseCtu + uiCUAddr, uiParameter, 4 * uiCurrPartNumQ ); + break; + case SIZE_2NxN: + memset( puhBaseCtu + uiCUAddr, uiParameter, 2 * uiCurrPartNumQ ); + break; + case SIZE_Nx2N: + memset( puhBaseCtu + uiCUAddr, uiParameter, uiCurrPartNumQ ); + memset( puhBaseCtu + uiCUAddr + 2 * uiCurrPartNumQ, uiParameter, uiCurrPartNumQ ); + break; + case SIZE_NxN: + memset( puhBaseCtu + uiCUAddr, uiParameter, uiCurrPartNumQ ); + break; + case SIZE_2NxnU: + if ( uiPUIdx == 0 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) ); + memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) ); + } + else if ( uiPUIdx == 1 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) ); + memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, ((uiCurrPartNumQ >> 1) + (uiCurrPartNumQ << 1)) ); + } + else + { + assert(0); + } + break; + case SIZE_2NxnD: + if ( uiPUIdx == 0 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, ((uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1)) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) ); + } + else if ( uiPUIdx == 1 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) ); + memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) ); + } + else + { + assert(0); + } + break; + case SIZE_nLx2N: + if ( uiPUIdx == 0 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + } + else if ( uiPUIdx == 1 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) ); + } + else + { + assert(0); + } + break; + case SIZE_nRx2N: + if ( uiPUIdx == 0 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) ); + memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + uiCurrPartNumQ + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + } + else if ( uiPUIdx == 1 ) + { + memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) ); + memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) ); + } + else + { + assert(0); + } + break; + default: + assert( 0 ); + break; + } +} + +Void TComDataCU::setMergeFlagSubParts ( Bool bMergeFlag, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( bMergeFlag, m_pbMergeFlag, uiAbsPartIdx, uiDepth, uiPartIdx ); +} + +Void TComDataCU::setMergeIndexSubParts ( UInt uiMergeIndex, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( uiMergeIndex, m_puhMergeIndex, uiAbsPartIdx, uiDepth, uiPartIdx ); +} + +Void TComDataCU::setInterDirSubParts( UInt uiDir, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( uiDir, m_puhInterDir, uiAbsPartIdx, uiDepth, uiPartIdx ); +} + +Void TComDataCU::setMVPIdxSubParts( Int iMVPIdx, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( iMVPIdx, m_apiMVPIdx[eRefPicList], uiAbsPartIdx, uiDepth, uiPartIdx ); +} + +Void TComDataCU::setMVPNumSubParts( Int iMVPNum, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) +{ + setSubPart( iMVPNum, m_apiMVPNum[eRefPicList], uiAbsPartIdx, uiDepth, uiPartIdx ); +} + + +Void TComDataCU::setTrIdxSubParts( UInt uiTrIdx, UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + + memset( m_puhTrIdx + uiAbsPartIdx, uiTrIdx, sizeof(UChar)*uiCurrPartNumb ); +} + +Void TComDataCU::setTransformSkipSubParts( const UInt useTransformSkip[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + + for(UInt i=0; igetNumPartitionsInCtu() >> (uiDepth << 1); + + memset( m_puhTransformSkip[compID] + uiAbsPartIdx, useTransformSkip, sizeof( UChar ) * uiCurrPartNumb ); +} + +Void TComDataCU::setTransformSkipPartRange ( UInt useTransformSkip, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ) +{ + memset((m_puhTransformSkip[compID] + uiAbsPartIdx), useTransformSkip, (sizeof(UChar) * uiCoveredPartIdxes)); +} + +Void TComDataCU::setCrossComponentPredictionAlphaPartRange( Char alphaValue, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ) +{ + memset((m_crossComponentPredictionAlpha[compID] + uiAbsPartIdx), alphaValue, (sizeof(Char) * uiCoveredPartIdxes)); +} + +Void TComDataCU::setExplicitRdpcmModePartRange ( UInt rdpcmMode, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ) +{ + memset((m_explicitRdpcmMode[compID] + uiAbsPartIdx), rdpcmMode, (sizeof(UChar) * uiCoveredPartIdxes)); +} + +Void TComDataCU::setSizeSubParts( UInt uiWidth, UInt uiHeight, UInt uiAbsPartIdx, UInt uiDepth ) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + + memset( m_puhWidth + uiAbsPartIdx, uiWidth, sizeof(UChar)*uiCurrPartNumb ); + memset( m_puhHeight + uiAbsPartIdx, uiHeight, sizeof(UChar)*uiCurrPartNumb ); +} + +UChar TComDataCU::getNumPartitions(const UInt uiAbsPartIdx) +{ + UChar iNumPart = 0; + + switch ( m_pePartSize[uiAbsPartIdx] ) + { + case SIZE_2Nx2N: iNumPart = 1; break; + case SIZE_2NxN: iNumPart = 2; break; + case SIZE_Nx2N: iNumPart = 2; break; + case SIZE_NxN: iNumPart = 4; break; + case SIZE_2NxnU: iNumPart = 2; break; + case SIZE_2NxnD: iNumPart = 2; break; + case SIZE_nLx2N: iNumPart = 2; break; + case SIZE_nRx2N: iNumPart = 2; break; + default: assert (0); break; + } + + return iNumPart; +} + +Void TComDataCU::getPartIndexAndSize( UInt uiPartIdx, UInt& ruiPartAddr, Int& riWidth, Int& riHeight ) +{ + switch ( m_pePartSize[0] ) + { + case SIZE_2NxN: + riWidth = getWidth(0); riHeight = getHeight(0) >> 1; ruiPartAddr = ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; + break; + case SIZE_Nx2N: + riWidth = getWidth(0) >> 1; riHeight = getHeight(0); ruiPartAddr = ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 2; + break; + case SIZE_NxN: + riWidth = getWidth(0) >> 1; riHeight = getHeight(0) >> 1; ruiPartAddr = ( m_uiNumPartition >> 2 ) * uiPartIdx; + break; + case SIZE_2NxnU: + riWidth = getWidth(0); + riHeight = ( uiPartIdx == 0 ) ? getHeight(0) >> 2 : ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ); + ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : m_uiNumPartition >> 3; + break; + case SIZE_2NxnD: + riWidth = getWidth(0); + riHeight = ( uiPartIdx == 0 ) ? ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ) : getHeight(0) >> 2; + ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 3); + break; + case SIZE_nLx2N: + riWidth = ( uiPartIdx == 0 ) ? getWidth(0) >> 2 : ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ); + riHeight = getHeight(0); + ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : m_uiNumPartition >> 4; + break; + case SIZE_nRx2N: + riWidth = ( uiPartIdx == 0 ) ? ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ) : getWidth(0) >> 2; + riHeight = getHeight(0); + ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : (m_uiNumPartition >> 2) + (m_uiNumPartition >> 4); + break; + default: + assert ( m_pePartSize[0] == SIZE_2Nx2N ); + riWidth = getWidth(0); riHeight = getHeight(0); ruiPartAddr = 0; + break; + } +} + + +Void TComDataCU::getMvField ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList, TComMvField& rcMvField ) +{ + if ( pcCU == NULL ) // OUT OF BOUNDARY + { + TComMv cZeroMv; + rcMvField.setMvField( cZeroMv, NOT_VALID ); + return; + } + + TComCUMvField* pcCUMvField = pcCU->getCUMvField( eRefPicList ); + rcMvField.setMvField( pcCUMvField->getMv( uiAbsPartIdx ), pcCUMvField->getRefIdx( uiAbsPartIdx ) ); +} + +Void TComDataCU::deriveLeftRightTopIdxGeneral ( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT ) +{ + ruiPartIdxLT = m_absZIdxInCtu + uiAbsPartIdx; + UInt uiPUWidth = 0; + + switch ( m_pePartSize[uiAbsPartIdx] ) + { + case SIZE_2Nx2N: uiPUWidth = m_puhWidth[uiAbsPartIdx]; break; + case SIZE_2NxN: uiPUWidth = m_puhWidth[uiAbsPartIdx]; break; + case SIZE_Nx2N: uiPUWidth = m_puhWidth[uiAbsPartIdx] >> 1; break; + case SIZE_NxN: uiPUWidth = m_puhWidth[uiAbsPartIdx] >> 1; break; + case SIZE_2NxnU: uiPUWidth = m_puhWidth[uiAbsPartIdx]; break; + case SIZE_2NxnD: uiPUWidth = m_puhWidth[uiAbsPartIdx]; break; + case SIZE_nLx2N: + if ( uiPartIdx == 0 ) + { + uiPUWidth = m_puhWidth[uiAbsPartIdx] >> 2; + } + else if ( uiPartIdx == 1 ) + { + uiPUWidth = (m_puhWidth[uiAbsPartIdx] >> 1) + (m_puhWidth[uiAbsPartIdx] >> 2); + } + else + { + assert(0); + } + break; + case SIZE_nRx2N: + if ( uiPartIdx == 0 ) + { + uiPUWidth = (m_puhWidth[uiAbsPartIdx] >> 1) + (m_puhWidth[uiAbsPartIdx] >> 2); + } + else if ( uiPartIdx == 1 ) + { + uiPUWidth = m_puhWidth[uiAbsPartIdx] >> 2; + } + else + { + assert(0); + } + break; + default: + assert (0); + break; + } + + ruiPartIdxRT = g_auiRasterToZscan [g_auiZscanToRaster[ ruiPartIdxLT ] + uiPUWidth / m_pcPic->getMinCUWidth() - 1 ]; +} + +Void TComDataCU::deriveLeftBottomIdxGeneral( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLB ) +{ + UInt uiPUHeight = 0; + switch ( m_pePartSize[uiAbsPartIdx] ) + { + case SIZE_2Nx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx]; break; + case SIZE_2NxN: uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 1; break; + case SIZE_Nx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx]; break; + case SIZE_NxN: uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 1; break; + case SIZE_2NxnU: + if ( uiPartIdx == 0 ) + { + uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 2; + } + else if ( uiPartIdx == 1 ) + { + uiPUHeight = (m_puhHeight[uiAbsPartIdx] >> 1) + (m_puhHeight[uiAbsPartIdx] >> 2); + } + else + { + assert(0); + } + break; + case SIZE_2NxnD: + if ( uiPartIdx == 0 ) + { + uiPUHeight = (m_puhHeight[uiAbsPartIdx] >> 1) + (m_puhHeight[uiAbsPartIdx] >> 2); + } + else if ( uiPartIdx == 1 ) + { + uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 2; + } + else + { + assert(0); + } + break; + case SIZE_nLx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx]; break; + case SIZE_nRx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx]; break; + default: + assert (0); + break; + } + + ruiPartIdxLB = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu + uiAbsPartIdx ] + ((uiPUHeight / m_pcPic->getMinCUHeight()) - 1)*m_pcPic->getNumPartInCtuWidth()]; +} + +Void TComDataCU::deriveLeftRightTopIdx ( UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT ) +{ + ruiPartIdxLT = m_absZIdxInCtu; + ruiPartIdxRT = g_auiRasterToZscan [g_auiZscanToRaster[ ruiPartIdxLT ] + m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1 ]; + + switch ( m_pePartSize[0] ) + { + case SIZE_2Nx2N: break; + case SIZE_2NxN: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; + break; + case SIZE_Nx2N: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 2; ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : m_uiNumPartition >> 2; + break; + case SIZE_NxN: + ruiPartIdxLT += ( m_uiNumPartition >> 2 ) * uiPartIdx; ruiPartIdxRT += ( m_uiNumPartition >> 2 ) * ( uiPartIdx - 1 ); + break; + case SIZE_2NxnU: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 3; + ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 3; + break; + case SIZE_2NxnD: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 1 ) + ( m_uiNumPartition >> 3 ); + ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 1 ) + ( m_uiNumPartition >> 3 ); + break; + case SIZE_nLx2N: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 4; + ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : ( m_uiNumPartition >> 2 ) + ( m_uiNumPartition >> 4 ); + break; + case SIZE_nRx2N: + ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 2 ) + ( m_uiNumPartition >> 4 ); + ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : m_uiNumPartition >> 4; + break; + default: + assert (0); + break; + } + +} + +Void TComDataCU::deriveLeftBottomIdx( UInt uiPartIdx, UInt& ruiPartIdxLB ) +{ + ruiPartIdxLB = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu ] + ( ((m_puhHeight[0] / m_pcPic->getMinCUHeight())>>1) - 1)*m_pcPic->getNumPartInCtuWidth()]; + + switch ( m_pePartSize[0] ) + { + case SIZE_2Nx2N: + ruiPartIdxLB += m_uiNumPartition >> 1; + break; + case SIZE_2NxN: + ruiPartIdxLB += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; + break; + case SIZE_Nx2N: + ruiPartIdxLB += ( uiPartIdx == 0 )? m_uiNumPartition >> 1 : (m_uiNumPartition >> 2)*3; + break; + case SIZE_NxN: + ruiPartIdxLB += ( m_uiNumPartition >> 2 ) * uiPartIdx; + break; + case SIZE_2NxnU: + ruiPartIdxLB += ( uiPartIdx == 0 ) ? -((Int)m_uiNumPartition >> 3) : m_uiNumPartition >> 1; + break; + case SIZE_2NxnD: + ruiPartIdxLB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3): m_uiNumPartition >> 1; + break; + case SIZE_nLx2N: + ruiPartIdxLB += ( uiPartIdx == 0 ) ? m_uiNumPartition >> 1 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 4); + break; + case SIZE_nRx2N: + ruiPartIdxLB += ( uiPartIdx == 0 ) ? m_uiNumPartition >> 1 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 2) + (m_uiNumPartition >> 4); + break; + default: + assert (0); + break; + } +} + +/** Derives the partition index of neighbouring bottom right block + * \param [in] eCUMode + * \param [in] uiPartIdx + * \param [out] ruiPartIdxRB + */ +Void TComDataCU::deriveRightBottomIdx( UInt uiPartIdx, UInt& ruiPartIdxRB ) +{ + ruiPartIdxRB = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu ] + ( ((m_puhHeight[0] / m_pcPic->getMinCUHeight())>>1) - 1)*m_pcPic->getNumPartInCtuWidth() + m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1]; + + switch ( m_pePartSize[0] ) + { + case SIZE_2Nx2N: + ruiPartIdxRB += m_uiNumPartition >> 1; + break; + case SIZE_2NxN: + ruiPartIdxRB += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; + break; + case SIZE_Nx2N: + ruiPartIdxRB += ( uiPartIdx == 0 )? m_uiNumPartition >> 2 : (m_uiNumPartition >> 1); + break; + case SIZE_NxN: + ruiPartIdxRB += ( m_uiNumPartition >> 2 ) * ( uiPartIdx - 1 ); + break; + case SIZE_2NxnU: + ruiPartIdxRB += ( uiPartIdx == 0 ) ? -((Int)m_uiNumPartition >> 3) : m_uiNumPartition >> 1; + break; + case SIZE_2NxnD: + ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3): m_uiNumPartition >> 1; + break; + case SIZE_nLx2N: + ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 3) + (m_uiNumPartition >> 4): m_uiNumPartition >> 1; + break; + case SIZE_nRx2N: + ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3) + (m_uiNumPartition >> 4) : m_uiNumPartition >> 1; + break; + default: + assert (0); + break; + } +} + +Void TComDataCU::deriveLeftRightTopIdxAdi ( UInt& ruiPartIdxLT, UInt& ruiPartIdxRT, UInt uiPartOffset, UInt uiPartDepth ) +{ + UInt uiNumPartInWidth = (m_puhWidth[0]/m_pcPic->getMinCUWidth())>>uiPartDepth; + ruiPartIdxLT = m_absZIdxInCtu + uiPartOffset; + ruiPartIdxRT = g_auiRasterToZscan[ g_auiZscanToRaster[ ruiPartIdxLT ] + uiNumPartInWidth - 1 ]; +} + +Void TComDataCU::deriveLeftBottomIdxAdi( UInt& ruiPartIdxLB, UInt uiPartOffset, UInt uiPartDepth ) +{ + UInt uiAbsIdx; + UInt uiMinCuWidth, uiWidthInMinCus; + + uiMinCuWidth = getPic()->getMinCUWidth(); + uiWidthInMinCus = (getWidth(0)/uiMinCuWidth)>>uiPartDepth; + uiAbsIdx = getZorderIdxInCtu()+uiPartOffset+(m_uiNumPartition>>(uiPartDepth<<1))-1; + uiAbsIdx = g_auiZscanToRaster[uiAbsIdx]-(uiWidthInMinCus-1); + ruiPartIdxLB = g_auiRasterToZscan[uiAbsIdx]; +} + +Bool TComDataCU::hasEqualMotion( UInt uiAbsPartIdx, TComDataCU* pcCandCU, UInt uiCandAbsPartIdx ) +{ + if ( getInterDir( uiAbsPartIdx ) != pcCandCU->getInterDir( uiCandAbsPartIdx ) ) + { + return false; + } + + for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) + { + if ( getInterDir( uiAbsPartIdx ) & ( 1 << uiRefListIdx ) ) + { + if ( getCUMvField( RefPicList( uiRefListIdx ) )->getMv( uiAbsPartIdx ) != pcCandCU->getCUMvField( RefPicList( uiRefListIdx ) )->getMv( uiCandAbsPartIdx ) || + getCUMvField( RefPicList( uiRefListIdx ) )->getRefIdx( uiAbsPartIdx ) != pcCandCU->getCUMvField( RefPicList( uiRefListIdx ) )->getRefIdx( uiCandAbsPartIdx ) ) + { + return false; + } + } + } + + return true; +} + +/** Constructs a list of merging candidates + * \param uiAbsPartIdx + * \param uiPUIdx + * \param uiDepth + * \param pcMvFieldNeighbours + * \param puhInterDirNeighbours + * \param numValidMergeCand + */ +Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx ) +{ + UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx; + Bool abCandIsInter[ MRG_MAX_NUM_CANDS ]; + for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui ) + { + abCandIsInter[ui] = false; + pcMvFieldNeighbours[ ( ui << 1 ) ].setRefIdx(NOT_VALID); + pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID); + } + numValidMergeCand = getSlice()->getMaxNumMergeCand(); + // compute the location of the current PU + Int xP, yP, nPSW, nPSH; + this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH); + + Int iCount = 0; + + UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB; + PartSize cCurPS = getPartitionSize( uiAbsPartIdx ); + deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT ); + deriveLeftBottomIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLB ); + + //left + UInt uiLeftPartIdx = 0; + TComDataCU* pcCULeft = 0; + pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB ); + + Bool isAvailableA1 = pcCULeft && + pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) && + !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) && + pcCULeft->isInter( uiLeftPartIdx ) ; + + if ( isAvailableA1 ) + { + abCandIsInter[iCount] = true; + // get Inter Dir + puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx ); + // get Mv from Left + pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); + if ( getSlice()->isInterB() ) + { + pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); + } + if ( mrgCandIdx == iCount ) + { + return; + } + iCount ++; + } + + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + // above + UInt uiAbovePartIdx = 0; + TComDataCU* pcCUAbove = 0; + pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT ); + + Bool isAvailableB1 = pcCUAbove && + pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) && + !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) && + pcCUAbove->isInter( uiAbovePartIdx ); + + if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) ) + { + abCandIsInter[iCount] = true; + // get Inter Dir + puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx ); + // get Mv from Left + pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); + if ( getSlice()->isInterB() ) + { + pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); + } + if ( mrgCandIdx == iCount ) + { + return; + } + iCount ++; + } + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + + // above right + UInt uiAboveRightPartIdx = 0; + TComDataCU* pcCUAboveRight = 0; + pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT ); + + Bool isAvailableB0 = pcCUAboveRight && + pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) && + pcCUAboveRight->isInter( uiAboveRightPartIdx ); + + if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) ) + { + abCandIsInter[iCount] = true; + // get Inter Dir + puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx ); + // get Mv from Left + pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); + if ( getSlice()->isInterB() ) + { + pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); + } + if ( mrgCandIdx == iCount ) + { + return; + } + iCount ++; + } + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + + //left bottom + UInt uiLeftBottomPartIdx = 0; + TComDataCU* pcCULeftBottom = 0; + pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB ); + + Bool isAvailableA0 = pcCULeftBottom && + pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) && + pcCULeftBottom->isInter( uiLeftBottomPartIdx ) ; + + if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) ) + { + abCandIsInter[iCount] = true; + // get Inter Dir + puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx ); + // get Mv from Left + pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); + if ( getSlice()->isInterB() ) + { + pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); + } + if ( mrgCandIdx == iCount ) + { + return; + } + iCount ++; + } + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + + // above left + if( iCount < 4 ) + { + UInt uiAboveLeftPartIdx = 0; + TComDataCU* pcCUAboveLeft = 0; + pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr ); + + Bool isAvailableB2 = pcCUAboveLeft && + pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) && + pcCUAboveLeft->isInter( uiAboveLeftPartIdx ); + + if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) + && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) ) + { + abCandIsInter[iCount] = true; + // get Inter Dir + puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx ); + // get Mv from Left + pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); + if ( getSlice()->isInterB() ) + { + pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); + } + if ( mrgCandIdx == iCount ) + { + return; + } + iCount ++; + } + } + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + + if ( getSlice()->getEnableTMVPFlag() ) + { + //>> MTK colocated-RightBottom + UInt uiPartIdxRB; + + deriveRightBottomIdx( uiPUIdx, uiPartIdxRB ); + + UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB]; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight(); + + TComMv cColMv; + Int iRefIdx; + Int ctuRsAddr = -1; + + if ( ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () ) // image boundary check + && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) + { + if ( ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 ) && // is not at the last column of CTU + ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 ) ) // is not at the last row of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + numPartInCtuWidth + 1 ]; + ctuRsAddr = getCtuRsAddr(); + } + else if ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 ) // is not at the last column of CTU But is last row of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ]; + } + else if ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 ) // is not at the last row of CTU But is last column of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ]; + ctuRsAddr = getCtuRsAddr() + 1; + } + else //is the right bottom corner of CTU + { + uiAbsPartAddr = 0; + } + } + + iRefIdx = 0; + + Bool bExistMV = false; + UInt uiPartIdxCenter; + Int dir = 0; + UInt uiArrayAddr = iCount; + xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter ); + bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_0, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx ); + if( bExistMV == false ) + { + bExistMV = xGetColMVP( REF_PIC_LIST_0, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx ); + } + if( bExistMV ) + { + dir |= 1; + pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx ); + } + + if ( getSlice()->isInterB() ) + { + bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_1, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx); + if( bExistMV == false ) + { + bExistMV = xGetColMVP( REF_PIC_LIST_1, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx ); + } + if( bExistMV ) + { + dir |= 2; + pcMvFieldNeighbours[ 2 * uiArrayAddr + 1 ].setMvField( cColMv, iRefIdx ); + } + } + + if (dir != 0) + { + puhInterDirNeighbours[uiArrayAddr] = dir; + abCandIsInter[uiArrayAddr] = true; + + if ( mrgCandIdx == iCount ) + { + return; + } + iCount++; + } + } + // early termination + if (iCount == getSlice()->getMaxNumMergeCand()) + { + return; + } + + UInt uiArrayAddr = iCount; + UInt uiCutoff = uiArrayAddr; + + if ( getSlice()->isInterB() ) + { + static const UInt NUM_PRIORITY_LIST=12; + static const UInt uiPriorityList0[NUM_PRIORITY_LIST] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3}; + static const UInt uiPriorityList1[NUM_PRIORITY_LIST] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2}; + + for (Int idx=0; idxgetMaxNumMergeCand(); idx++) + { + assert(idxgetRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() ); + Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() ); + if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv()) + { + abCandIsInter[uiArrayAddr] = false; + } + else + { + uiArrayAddr++; + } + } + } + } + // early termination + if (uiArrayAddr == getSlice()->getMaxNumMergeCand()) + { + return; + } + + Int iNumRefIdx = (getSlice()->isInterB()) ? min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0); + + Int r = 0; + Int refcnt = 0; + while (uiArrayAddr < getSlice()->getMaxNumMergeCand()) + { + abCandIsInter[uiArrayAddr] = true; + puhInterDirNeighbours[uiArrayAddr] = 1; + pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r); + + if ( getSlice()->isInterB() ) + { + puhInterDirNeighbours[uiArrayAddr] = 3; + pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r); + } + uiArrayAddr++; + + if ( refcnt == iNumRefIdx - 1 ) + { + r = 0; + } + else + { + ++r; + ++refcnt; + } + } + numValidMergeCand = uiArrayAddr; +} + +/** Check whether the current PU and a spatial neighboring PU are in a same ME region. + * \param xN, xN location of the upper-left corner pixel of a neighboring PU + * \param xP, yP location of the upper-left corner pixel of the current PU + * \returns Bool + */ +Bool TComDataCU::isDiffMER(Int xN, Int yN, Int xP, Int yP) +{ + + UInt plevel = this->getSlice()->getPPS()->getLog2ParallelMergeLevelMinus2() + 2; + if ((xN>>plevel)!= (xP>>plevel)) + { + return true; + } + if ((yN>>plevel)!= (yP>>plevel)) + { + return true; + } + return false; +} + +/** calculate the location of upper-left corner pixel and size of the current PU. + * \param partIdx PU index within a CU + * \param xP, yP location of the upper-left corner pixel of the current PU + * \param PSW, nPSH size of the curren PU + * \returns Void + */ +Void TComDataCU::getPartPosition( UInt partIdx, Int& xP, Int& yP, Int& nPSW, Int& nPSH) +{ + UInt col = m_uiCUPelX; + UInt row = m_uiCUPelY; + + switch ( m_pePartSize[0] ) + { + case SIZE_2NxN: + nPSW = getWidth(0); + nPSH = getHeight(0) >> 1; + xP = col; + yP = (partIdx ==0)? row: row + nPSH; + break; + case SIZE_Nx2N: + nPSW = getWidth(0) >> 1; + nPSH = getHeight(0); + xP = (partIdx ==0)? col: col + nPSW; + yP = row; + break; + case SIZE_NxN: + nPSW = getWidth(0) >> 1; + nPSH = getHeight(0) >> 1; + xP = col + (partIdx&0x1)*nPSW; + yP = row + (partIdx>>1)*nPSH; + break; + case SIZE_2NxnU: + nPSW = getWidth(0); + nPSH = ( partIdx == 0 ) ? getHeight(0) >> 2 : ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ); + xP = col; + yP = (partIdx ==0)? row: row + getHeight(0) - nPSH; + + break; + case SIZE_2NxnD: + nPSW = getWidth(0); + nPSH = ( partIdx == 0 ) ? ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ) : getHeight(0) >> 2; + xP = col; + yP = (partIdx ==0)? row: row + getHeight(0) - nPSH; + break; + case SIZE_nLx2N: + nPSW = ( partIdx == 0 ) ? getWidth(0) >> 2 : ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ); + nPSH = getHeight(0); + xP = (partIdx ==0)? col: col + getWidth(0) - nPSW; + yP = row; + break; + case SIZE_nRx2N: + nPSW = ( partIdx == 0 ) ? ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ) : getWidth(0) >> 2; + nPSH = getHeight(0); + xP = (partIdx ==0)? col: col + getWidth(0) - nPSW; + yP = row; + break; + default: + assert ( m_pePartSize[0] == SIZE_2Nx2N ); + nPSW = getWidth(0); + nPSH = getHeight(0); + xP = col ; + yP = row ; + + break; + } +} + +/** Constructs a list of candidates for AMVP + * \param uiPartIdx + * \param uiPartAddr + * \param eRefPicList + * \param iRefIdx + * \param pInfo + */ +Void TComDataCU::fillMvpCand ( UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, Int iRefIdx, AMVPInfo* pInfo ) +{ + TComMv cMvPred; + Bool bAddedSmvp = false; + + pInfo->iN = 0; + if (iRefIdx < 0) + { + return; + } + + //-- Get Spatial MV + UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB; + const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); + const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight(); + Bool bAdded = false; + + deriveLeftRightTopIdx( uiPartIdx, uiPartIdxLT, uiPartIdxRT ); + deriveLeftBottomIdx( uiPartIdx, uiPartIdxLB ); + + TComDataCU* tmpCU = NULL; + UInt idx; + tmpCU = getPUBelowLeft(idx, uiPartIdxLB); + bAddedSmvp = (tmpCU != NULL) && (tmpCU->isInter(idx)); + + if (!bAddedSmvp) + { + tmpCU = getPULeft(idx, uiPartIdxLB); + bAddedSmvp = (tmpCU != NULL) && (tmpCU->isInter(idx)); + } + + // Left predictor search + bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT); + if (!bAdded) + { + bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT ); + } + + if(!bAdded) + { + bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT); + if (!bAdded) + { + xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT ); + } + } + + // Above predictor search + bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT); + + if (!bAdded) + { + bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE); + } + + if(!bAdded) + { + xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT); + } + + if(!bAddedSmvp) + { + bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT); + if (!bAdded) + { + bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE); + } + + if(!bAdded) + { + xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT); + } + } + + if ( pInfo->iN == 2 ) + { + if ( pInfo->m_acMvCand[ 0 ] == pInfo->m_acMvCand[ 1 ] ) + { + pInfo->iN = 1; + } + } + + if ( getSlice()->getEnableTMVPFlag() ) + { + // Get Temporal Motion Predictor + Int iRefIdx_Col = iRefIdx; + TComMv cColMv; + UInt uiPartIdxRB; + UInt uiAbsPartIdx; + UInt uiAbsPartAddr; + + deriveRightBottomIdx( uiPartIdx, uiPartIdxRB ); + uiAbsPartAddr = m_absZIdxInCtu + uiPartAddr; + + //---- co-located RightBottom Temporal Predictor (H) ---// + uiAbsPartIdx = g_auiZscanToRaster[uiPartIdxRB]; + Int ctuRsAddr = -1; + if ( ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdx] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () ) // image boundary check + && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdx] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) + { + if ( ( uiAbsPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 ) && // is not at the last column of CTU + ( uiAbsPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) ) // is not at the last row of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + numPartInCtuWidth + 1 ]; + ctuRsAddr = getCtuRsAddr(); + } + else if ( uiAbsPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 ) // is not at the last column of CTU But is last row of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdx + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ]; + } + else if ( uiAbsPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) // is not at the last row of CTU But is last column of CTU + { + uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + 1 ]; + ctuRsAddr = getCtuRsAddr() + 1; + } + else //is the right bottom corner of CTU + { + uiAbsPartAddr = 0; + } + } + if ( ctuRsAddr >= 0 && xGetColMVP( eRefPicList, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx_Col ) ) + { + pInfo->m_acMvCand[pInfo->iN++] = cColMv; + } + else + { + UInt uiPartIdxCenter; + xDeriveCenterIdx( uiPartIdx, uiPartIdxCenter ); + if (xGetColMVP( eRefPicList, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx_Col )) + { + pInfo->m_acMvCand[pInfo->iN++] = cColMv; + } + } + //---- co-located RightBottom Temporal Predictor ---// + } + + if (pInfo->iN > AMVP_MAX_NUM_CANDS) + { + pInfo->iN = AMVP_MAX_NUM_CANDS; + } + + while (pInfo->iN < AMVP_MAX_NUM_CANDS) + { + pInfo->m_acMvCand[pInfo->iN].set(0,0); + pInfo->iN++; + } + return ; +} + + +Bool TComDataCU::isBipredRestriction(UInt puIdx) +{ + Int width = 0; + Int height = 0; + UInt partAddr; + + getPartIndexAndSize( puIdx, partAddr, width, height ); + if ( getWidth(0) == 8 && (width < 8 || height < 8) ) + { + return true; + } + return false; +} + + +Void TComDataCU::clipMv (TComMv& rcMv) +{ + Int iMvShift = 2; + Int iOffset = 8; + Int iHorMax = ( m_pcSlice->getSPS()->getPicWidthInLumaSamples() + iOffset - m_uiCUPelX - 1 ) << iMvShift; + Int iHorMin = ( -(Int)g_uiMaxCUWidth - iOffset - (Int)m_uiCUPelX + 1 ) << iMvShift; + + Int iVerMax = ( m_pcSlice->getSPS()->getPicHeightInLumaSamples() + iOffset - m_uiCUPelY - 1 ) << iMvShift; + Int iVerMin = ( -(Int)g_uiMaxCUHeight - iOffset - (Int)m_uiCUPelY + 1 ) << iMvShift; + + rcMv.setHor( min (iHorMax, max (iHorMin, rcMv.getHor())) ); + rcMv.setVer( min (iVerMax, max (iVerMin, rcMv.getVer())) ); +} + + +UInt TComDataCU::getIntraSizeIdx(UInt uiAbsPartIdx) +{ + UInt uiShift = ( m_pePartSize[uiAbsPartIdx]==SIZE_NxN ? 1 : 0 ); + + UChar uiWidth = m_puhWidth[uiAbsPartIdx]>>uiShift; + UInt uiCnt = 0; + while( uiWidth ) + { + uiCnt++; + uiWidth>>=1; + } + uiCnt-=2; + return uiCnt > 6 ? 6 : uiCnt; +} + +Void TComDataCU::clearCbf( UInt uiIdx, ComponentID compID, UInt uiNumParts ) +{ + memset( &m_puhCbf[compID][uiIdx], 0, sizeof(UChar)*uiNumParts); +} + +/** Set a I_PCM flag for all sub-partitions of a partition. + * \param bIpcmFlag I_PCM flag + * \param uiAbsPartIdx patition index + * \param uiDepth CU depth + * \returns Void + */ +Void TComDataCU::setIPCMFlagSubParts (Bool bIpcmFlag, UInt uiAbsPartIdx, UInt uiDepth) +{ + UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1); + + memset(m_pbIPCMFlag + uiAbsPartIdx, bIpcmFlag, sizeof(Bool)*uiCurrPartNumb ); +} + +/** Test whether the current block is skipped + * \param uiPartIdx Block index + * \returns Flag indicating whether the block is skipped + */ +Bool TComDataCU::isSkipped( UInt uiPartIdx ) +{ + return ( getSkipFlag( uiPartIdx ) ); +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + +Bool TComDataCU::xAddMVPCand( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir ) +{ + TComDataCU* pcTmpCU = NULL; + UInt uiIdx; + switch( eDir ) + { + case MD_LEFT: + { + pcTmpCU = getPULeft(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE: + { + pcTmpCU = getPUAbove(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE_RIGHT: + { + pcTmpCU = getPUAboveRight(uiIdx, uiPartUnitIdx); + break; + } + case MD_BELOW_LEFT: + { + pcTmpCU = getPUBelowLeft(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE_LEFT: + { + pcTmpCU = getPUAboveLeft(uiIdx, uiPartUnitIdx); + break; + } + default: + { + break; + } + } + + if ( pcTmpCU == NULL ) + { + return false; + } + + if ( pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) >= 0 && m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC() == pcTmpCU->getSlice()->getRefPOC( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) )) + { + TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList)->getMv(uiIdx); + + pInfo->m_acMvCand[ pInfo->iN++] = cMvPred; + return true; + } + + RefPicList eRefPicList2nd = REF_PIC_LIST_0; + if( eRefPicList == REF_PIC_LIST_0 ) + { + eRefPicList2nd = REF_PIC_LIST_1; + } + else if ( eRefPicList == REF_PIC_LIST_1) + { + eRefPicList2nd = REF_PIC_LIST_0; + } + + + Int iCurrRefPOC = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC(); + Int iNeibRefPOC; + + + if( pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) >= 0 ) + { + iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) ); + if( iNeibRefPOC == iCurrRefPOC ) // Same Reference Frame But Diff List// + { + TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList2nd)->getMv(uiIdx); + pInfo->m_acMvCand[ pInfo->iN++] = cMvPred; + return true; + } + } + return false; +} + +/** + * \param pInfo + * \param eRefPicList + * \param iRefIdx + * \param uiPartUnitIdx + * \param eDir + * \returns Bool + */ +Bool TComDataCU::xAddMVPCandOrder( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir ) +{ + TComDataCU* pcTmpCU = NULL; + UInt uiIdx; + switch( eDir ) + { + case MD_LEFT: + { + pcTmpCU = getPULeft(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE: + { + pcTmpCU = getPUAbove(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE_RIGHT: + { + pcTmpCU = getPUAboveRight(uiIdx, uiPartUnitIdx); + break; + } + case MD_BELOW_LEFT: + { + pcTmpCU = getPUBelowLeft(uiIdx, uiPartUnitIdx); + break; + } + case MD_ABOVE_LEFT: + { + pcTmpCU = getPUAboveLeft(uiIdx, uiPartUnitIdx); + break; + } + default: + { + break; + } + } + + if ( pcTmpCU == NULL ) + { + return false; + } + + RefPicList eRefPicList2nd = REF_PIC_LIST_0; + if( eRefPicList == REF_PIC_LIST_0 ) + { + eRefPicList2nd = REF_PIC_LIST_1; + } + else if ( eRefPicList == REF_PIC_LIST_1) + { + eRefPicList2nd = REF_PIC_LIST_0; + } + + Int iCurrPOC = m_pcSlice->getPOC(); + Int iCurrRefPOC = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC(); + Int iNeibPOC = iCurrPOC; + Int iNeibRefPOC; + Bool bIsCurrRefLongTerm = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getIsLongTerm(); + Bool bIsNeibRefLongTerm = false; + + //--------------- V1 (END) ------------------// + if( pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) >= 0) + { + iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) ); + TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList)->getMv(uiIdx); + TComMv rcMv; + + bIsNeibRefLongTerm = pcTmpCU->getSlice()->getRefPic( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) )->getIsLongTerm(); + if ( bIsCurrRefLongTerm == bIsNeibRefLongTerm ) + { + if ( bIsCurrRefLongTerm || bIsNeibRefLongTerm ) + { + rcMv = cMvPred; + } + else + { + Int iScale = xGetDistScaleFactor( iCurrPOC, iCurrRefPOC, iNeibPOC, iNeibRefPOC ); + if ( iScale == 4096 ) + { + rcMv = cMvPred; + } + else + { + rcMv = cMvPred.scaleMv( iScale ); + } + } + + pInfo->m_acMvCand[ pInfo->iN++] = rcMv; + return true; + } + } + //---------------------- V2(END) --------------------// + if( pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) >= 0) + { + iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) ); + TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList2nd)->getMv(uiIdx); + TComMv rcMv; + + bIsNeibRefLongTerm = pcTmpCU->getSlice()->getRefPic( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) )->getIsLongTerm(); + if ( bIsCurrRefLongTerm == bIsNeibRefLongTerm ) + { + if ( bIsCurrRefLongTerm || bIsNeibRefLongTerm ) + { + rcMv = cMvPred; + } + else + { + Int iScale = xGetDistScaleFactor( iCurrPOC, iCurrRefPOC, iNeibPOC, iNeibRefPOC ); + if ( iScale == 4096 ) + { + rcMv = cMvPred; + } + else + { + rcMv = cMvPred.scaleMv( iScale ); + } + } + + pInfo->m_acMvCand[ pInfo->iN++] = rcMv; + return true; + } + } + //---------------------- V3(END) --------------------// + return false; +} + +/** + * \param eRefPicList + * \param uiCUAddr + * \param uiPartUnitIdx + * \param riRefIdx + * \returns Bool + */ +Bool TComDataCU::xGetColMVP( RefPicList eRefPicList, Int ctuRsAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx ) +{ + UInt uiAbsPartAddr = uiPartUnitIdx; + + RefPicList eColRefPicList; + Int iColPOC, iColRefPOC, iCurrPOC, iCurrRefPOC, iScale; + TComMv cColMv; + + // use coldir. + TComPic *pColPic = getSlice()->getRefPic( RefPicList(getSlice()->isInterB() ? 1-getSlice()->getColFromL0Flag() : 0), getSlice()->getColRefIdx()); + TComDataCU *pColCtu = pColPic->getCtu( ctuRsAddr ); + if(pColCtu->getPic()==0||pColCtu->getPartitionSize(uiPartUnitIdx)==NUMBER_OF_PART_SIZES) + { + return false; + } + iCurrPOC = m_pcSlice->getPOC(); + iColPOC = pColCtu->getSlice()->getPOC(); + + if (!pColCtu->isInter(uiAbsPartAddr)) + { + return false; + } + + eColRefPicList = getSlice()->getCheckLDC() ? eRefPicList : RefPicList(getSlice()->getColFromL0Flag()); + + Int iColRefIdx = pColCtu->getCUMvField(RefPicList(eColRefPicList))->getRefIdx(uiAbsPartAddr); + + if (iColRefIdx < 0 ) + { + eColRefPicList = RefPicList(1 - eColRefPicList); + iColRefIdx = pColCtu->getCUMvField(RefPicList(eColRefPicList))->getRefIdx(uiAbsPartAddr); + + if (iColRefIdx < 0 ) + { + return false; + } + } + + // Scale the vector. + iColRefPOC = pColCtu->getSlice()->getRefPOC(eColRefPicList, iColRefIdx); + cColMv = pColCtu->getCUMvField(eColRefPicList)->getMv(uiAbsPartAddr); + + iCurrRefPOC = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getPOC(); + + Bool bIsCurrRefLongTerm = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getIsLongTerm(); + Bool bIsColRefLongTerm = pColCtu->getSlice()->getIsUsedAsLongTerm(eColRefPicList, iColRefIdx); + + if ( bIsCurrRefLongTerm != bIsColRefLongTerm ) + { + return false; + } + + if ( bIsCurrRefLongTerm || bIsColRefLongTerm ) + { + rcMv = cColMv; + } + else + { + iScale = xGetDistScaleFactor(iCurrPOC, iCurrRefPOC, iColPOC, iColRefPOC); + if ( iScale == 4096 ) + { + rcMv = cColMv; + } + else + { + rcMv = cColMv.scaleMv( iScale ); + } + } + + return true; +} + +UInt TComDataCU::xGetMvdBits(TComMv cMvd) +{ + return ( xGetComponentBits(cMvd.getHor()) + xGetComponentBits(cMvd.getVer()) ); +} + +UInt TComDataCU::xGetComponentBits(Int iVal) +{ + UInt uiLength = 1; + UInt uiTemp = ( iVal <= 0) ? (-iVal<<1)+1: (iVal<<1); + + assert ( uiTemp ); + + while ( 1 != uiTemp ) + { + uiTemp >>= 1; + uiLength += 2; + } + + return uiLength; +} + + +Int TComDataCU::xGetDistScaleFactor(Int iCurrPOC, Int iCurrRefPOC, Int iColPOC, Int iColRefPOC) +{ + Int iDiffPocD = iColPOC - iColRefPOC; + Int iDiffPocB = iCurrPOC - iCurrRefPOC; + + if( iDiffPocD == iDiffPocB ) + { + return 4096; + } + else + { + Int iTDB = Clip3( -128, 127, iDiffPocB ); + Int iTDD = Clip3( -128, 127, iDiffPocD ); + Int iX = (0x4000 + abs(iTDD/2)) / iTDD; + Int iScale = Clip3( -4096, 4095, (iTDB * iX + 32) >> 6 ); + return iScale; + } +} + +/** + * \param eCUMode + * \param uiPartIdx + * \param ruiPartIdxCenter + * \returns Void + */ +Void TComDataCU::xDeriveCenterIdx( UInt uiPartIdx, UInt& ruiPartIdxCenter ) +{ + UInt uiPartAddr; + Int iPartWidth; + Int iPartHeight; + getPartIndexAndSize( uiPartIdx, uiPartAddr, iPartWidth, iPartHeight); + + ruiPartIdxCenter = m_absZIdxInCtu+uiPartAddr; // partition origin. + ruiPartIdxCenter = g_auiRasterToZscan[ g_auiZscanToRaster[ ruiPartIdxCenter ] + + ( iPartHeight/m_pcPic->getMinCUHeight() )/2*m_pcPic->getNumPartInCtuWidth() + + ( iPartWidth/m_pcPic->getMinCUWidth() )/2]; +} + +Void TComDataCU::compressMV() +{ + Int scaleFactor = 4 * AMVP_DECIMATION_FACTOR / m_unitSize; + if (scaleFactor > 0) + { + for(UInt i=0; igetChromaFormat(); + + const UInt maximumWidth = MDCS_MAXIMUM_WIDTH >> getComponentScaleX(compID, format); + const UInt maximumHeight = MDCS_MAXIMUM_HEIGHT >> getComponentScaleY(compID, format); + + if ((uiWidth > maximumWidth) || (uiHeight > maximumHeight)) return SCAN_DIAG; + + //------------------------------------------------ + + //otherwise, select the appropriate mode + + UInt uiDirMode = getIntraDir(toChannelType(compID), uiAbsPartIdx); + + if (uiDirMode==DM_CHROMA_IDX) + { + uiDirMode = getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, getPic()->getChromaFormat())); + } + + if (isChroma(compID) && (format == CHROMA_422)) + { + uiDirMode = g_chroma422IntraAngleMappingTable[uiDirMode]; + } + + //------------------ + + if (abs((Int)uiDirMode - VER_IDX) <= MDCS_ANGLE_LIMIT) return SCAN_HOR; + else if (abs((Int)uiDirMode - HOR_IDX) <= MDCS_ANGLE_LIMIT) return SCAN_VER; + else return SCAN_DIAG; +} + +//! \} diff --git a/jctvc/TLibCommon/TComDataCU.h b/jctvc/TLibCommon/TComDataCU.h new file mode 100644 index 0000000..c75ca2e --- /dev/null +++ b/jctvc/TLibCommon/TComDataCU.h @@ -0,0 +1,570 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComDataCU.h + \brief CU data structure (header) + \todo not all entities are documented +*/ + +#ifndef __TCOMDATACU__ +#define __TCOMDATACU__ + +#include + +// Include files +#include "CommonDef.h" +#include "TComMotionInfo.h" +#include "TComSlice.h" +#include "TComRdCost.h" +#include "TComPattern.h" + +#include +#include + +//! \ingroup TLibCommon +//! \{ + +class TComTU; // forward declaration + +static const UInt NUM_MOST_PROBABLE_MODES=3; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// CU data structure class +class TComDataCU +{ +private: + + // ------------------------------------------------------------------------------------------------------------------- + // class pointers + // ------------------------------------------------------------------------------------------------------------------- + + TComPic* m_pcPic; ///< picture class pointer + TComSlice* m_pcSlice; ///< slice header pointer + + // ------------------------------------------------------------------------------------------------------------------- + // CU description + // ------------------------------------------------------------------------------------------------------------------- + + UInt m_ctuRsAddr; ///< CTU (also known as LCU) address in a slice (Raster-scan address, as opposed to tile-scan/encoding order). + UInt m_absZIdxInCtu; ///< absolute address in a CTU. It's Z scan order + UInt m_uiCUPelX; ///< CU position in a pixel (X) + UInt m_uiCUPelY; ///< CU position in a pixel (Y) + UInt m_uiNumPartition; ///< total number of minimum partitions in a CU + UChar* m_puhWidth; ///< array of widths + UChar* m_puhHeight; ///< array of heights + UChar* m_puhDepth; ///< array of depths + Int m_unitSize; ///< size of a "minimum partition" + + // ------------------------------------------------------------------------------------------------------------------- + // CU data + // ------------------------------------------------------------------------------------------------------------------- + + Bool* m_skipFlag; ///< array of skip flags + Char* m_pePartSize; ///< array of partition sizes + Char* m_pePredMode; ///< array of prediction modes + Char* m_crossComponentPredictionAlpha[MAX_NUM_COMPONENT]; ///< array of cross-component prediction alpha values + Bool* m_CUTransquantBypass; ///< array of cu_transquant_bypass flags + Char* m_phQP; ///< array of QP values + UChar* m_ChromaQpAdj; ///< array of chroma QP adjustments (indexed) + UInt m_codedChromaQpAdj; + UChar* m_puhTrIdx; ///< array of transform indices + UChar* m_puhTransformSkip[MAX_NUM_COMPONENT];///< array of transform skipping flags + UChar* m_puhCbf[MAX_NUM_COMPONENT]; ///< array of coded block flags (CBF) + TComCUMvField m_acCUMvField[NUM_REF_PIC_LIST_01]; ///< array of motion vectors. + TCoeff* m_pcTrCoeff[MAX_NUM_COMPONENT]; ///< array of transform coefficient buffers (0->Y, 1->Cb, 2->Cr) +#if ADAPTIVE_QP_SELECTION + TCoeff* m_pcArlCoeff[MAX_NUM_COMPONENT]; // ARL coefficient buffer (0->Y, 1->Cb, 2->Cr) + static TCoeff* m_pcGlbArlCoeff[MAX_NUM_COMPONENT]; // global ARL buffer + Bool m_ArlCoeffIsAliasedAllocation; ///< ARL coefficient buffer is an alias of the global buffer and must not be free()'d +#endif + + Pel* m_pcIPCMSample[MAX_NUM_COMPONENT]; ///< PCM sample buffer (0->Y, 1->Cb, 2->Cr) + + // ------------------------------------------------------------------------------------------------------------------- + // neighbour access variables + // ------------------------------------------------------------------------------------------------------------------- + + TComDataCU* m_pCtuAboveLeft; ///< pointer of above-left CTU. + TComDataCU* m_pCtuAboveRight; ///< pointer of above-right CTU. + TComDataCU* m_pCtuAbove; ///< pointer of above CTU. + TComDataCU* m_pCtuLeft; ///< pointer of left CTU + TComDataCU* m_apcCUColocated[NUM_REF_PIC_LIST_01]; ///< pointer of temporally colocated CU's for both directions + TComMvField m_cMvFieldA; ///< motion vector of position A + TComMvField m_cMvFieldB; ///< motion vector of position B + TComMvField m_cMvFieldC; ///< motion vector of position C + TComMv m_cMvPred; ///< motion vector predictor + + // ------------------------------------------------------------------------------------------------------------------- + // coding tool information + // ------------------------------------------------------------------------------------------------------------------- + + Bool* m_pbMergeFlag; ///< array of merge flags + UChar* m_puhMergeIndex; ///< array of merge candidate indices +#if AMP_MRG + Bool m_bIsMergeAMP; +#endif + UChar* m_puhIntraDir[MAX_NUM_CHANNEL_TYPE]; // 0-> Luma, 1-> Chroma + UChar* m_puhInterDir; ///< array of inter directions + Char* m_apiMVPIdx[NUM_REF_PIC_LIST_01]; ///< array of motion vector predictor candidates + Char* m_apiMVPNum[NUM_REF_PIC_LIST_01]; ///< array of number of possible motion vectors predictors + Bool* m_pbIPCMFlag; ///< array of intra_pcm flags + + // ------------------------------------------------------------------------------------------------------------------- + // misc. variables + // ------------------------------------------------------------------------------------------------------------------- + + Bool m_bDecSubCu; ///< indicates decoder-mode + Double m_dTotalCost; ///< sum of partition RD costs + Distortion m_uiTotalDistortion; ///< sum of partition distortion + UInt m_uiTotalBits; ///< sum of partition bits + UInt m_uiTotalBins; ///< sum of partition bins + Char m_codedQP; + UChar* m_explicitRdpcmMode[MAX_NUM_COMPONENT]; ///< Stores the explicit RDPCM mode for all TUs belonging to this CU + +protected: + + /// add possible motion vector predictor candidates + Bool xAddMVPCand ( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir ); + Bool xAddMVPCandOrder ( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir ); + + Void deriveRightBottomIdx ( UInt uiPartIdx, UInt& ruiPartIdxRB ); + Bool xGetColMVP( RefPicList eRefPicList, Int ctuRsAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx ); + + /// compute required bits to encode MVD (used in AMVP) + UInt xGetMvdBits ( TComMv cMvd ); + UInt xGetComponentBits ( Int iVal ); + + /// compute scaling factor from POC difference + Int xGetDistScaleFactor ( Int iCurrPOC, Int iCurrRefPOC, Int iColPOC, Int iColRefPOC ); + + Void xDeriveCenterIdx( UInt uiPartIdx, UInt& ruiPartIdxCenter ); + +public: + TComDataCU(); + virtual ~TComDataCU(); + + // ------------------------------------------------------------------------------------------------------------------- + // create / destroy / initialize / copy + // ------------------------------------------------------------------------------------------------------------------- + + Void create ( ChromaFormat chromaFormatIDC, UInt uiNumPartition, UInt uiWidth, UInt uiHeight, Bool bDecSubCu, Int unitSize +#if ADAPTIVE_QP_SELECTION + , Bool bGlobalRMARLBuffer = false +#endif + ); + Void destroy (); + + Void initCtu ( TComPic* pcPic, UInt ctuRsAddr ); + Void initEstData ( const UInt uiDepth, const Int qp, const Bool bTransquantBypass ); + Void initSubCU ( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth, Int qp ); + Void setOutsideCUPart ( UInt uiAbsPartIdx, UInt uiDepth ); + + Void copySubCU ( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth ); + Void copyInterPredInfoFrom ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList ); + Void copyPartFrom ( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth ); + + Void copyToPic ( UChar uiDepth ); + Void copyToPic ( UChar uiDepth, UInt uiPartIdx, UInt uiPartDepth ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for CU description + // ------------------------------------------------------------------------------------------------------------------- + + TComPic* getPic () { return m_pcPic; } + const TComPic* getPic () const { return m_pcPic; } + TComSlice* getSlice () { return m_pcSlice; } + const TComSlice* getSlice () const { return m_pcSlice; } + UInt& getCtuRsAddr () { return m_ctuRsAddr; } + UInt getCtuRsAddr () const { return m_ctuRsAddr; } + UInt getZorderIdxInCtu () const { return m_absZIdxInCtu; } + UInt getCUPelX () const { return m_uiCUPelX; } + UInt getCUPelY () const { return m_uiCUPelY; } + + UChar* getDepth () { return m_puhDepth; } + UChar getDepth ( UInt uiIdx ) const { return m_puhDepth[uiIdx]; } + Void setDepth ( UInt uiIdx, UChar uh ) { m_puhDepth[uiIdx] = uh; } + + Void setDepthSubParts ( UInt uiDepth, UInt uiAbsPartIdx ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for CU data + // ------------------------------------------------------------------------------------------------------------------- + + Char* getPartitionSize () { return m_pePartSize; } + PartSize getPartitionSize ( UInt uiIdx ) { return static_cast( m_pePartSize[uiIdx] ); } + Void setPartitionSize ( UInt uiIdx, PartSize uh){ m_pePartSize[uiIdx] = uh; } + Void setPartSizeSubParts ( PartSize eMode, UInt uiAbsPartIdx, UInt uiDepth ); + Void setCUTransquantBypassSubParts( Bool flag, UInt uiAbsPartIdx, UInt uiDepth ); + + Bool* getSkipFlag () { return m_skipFlag; } + Bool getSkipFlag (UInt idx) { return m_skipFlag[idx]; } + Void setSkipFlag ( UInt idx, Bool skip) { m_skipFlag[idx] = skip; } + Void setSkipFlagSubParts ( Bool skip, UInt absPartIdx, UInt depth ); + + Char* getPredictionMode () { return m_pePredMode; } + PredMode getPredictionMode ( UInt uiIdx ) { return static_cast( m_pePredMode[uiIdx] ); } + Void setPredictionMode ( UInt uiIdx, PredMode uh){ m_pePredMode[uiIdx] = uh; } + Void setPredModeSubParts ( PredMode eMode, UInt uiAbsPartIdx, UInt uiDepth ); + + Char* getCrossComponentPredictionAlpha( ComponentID compID ) { return m_crossComponentPredictionAlpha[compID]; } + Char getCrossComponentPredictionAlpha( UInt uiIdx, ComponentID compID ) { return m_crossComponentPredictionAlpha[compID][uiIdx]; } + + Bool* getCUTransquantBypass () { return m_CUTransquantBypass; } + Bool getCUTransquantBypass( UInt uiIdx ) { return m_CUTransquantBypass[uiIdx]; } + + UChar* getWidth () { return m_puhWidth; } + UChar getWidth ( UInt uiIdx ) { return m_puhWidth[uiIdx]; } + Void setWidth ( UInt uiIdx, UChar uh ) { m_puhWidth[uiIdx] = uh; } + + UChar* getHeight () { return m_puhHeight; } + UChar getHeight ( UInt uiIdx ) { return m_puhHeight[uiIdx]; } + Void setHeight ( UInt uiIdx, UChar uh ) { m_puhHeight[uiIdx] = uh; } + + Void setSizeSubParts ( UInt uiWidth, UInt uiHeight, UInt uiAbsPartIdx, UInt uiDepth ); + + Char* getQP () { return m_phQP; } + Char getQP ( UInt uiIdx ) const { return m_phQP[uiIdx]; } + Void setQP ( UInt uiIdx, Char value ){ m_phQP[uiIdx] = value; } + Void setQPSubParts ( Int qp, UInt uiAbsPartIdx, UInt uiDepth ); + Int getLastValidPartIdx ( Int iAbsPartIdx ); + Char getLastCodedQP ( UInt uiAbsPartIdx ); + Void setQPSubCUs ( Int qp, UInt absPartIdx, UInt depth, Bool &foundNonZeroCbf ); + Void setCodedQP ( Char qp ) { m_codedQP = qp; } + Char getCodedQP () { return m_codedQP; } + + UChar* getChromaQpAdj () { return m_ChromaQpAdj; } + UChar getChromaQpAdj (Int idx) const { return m_ChromaQpAdj[idx]; } + Void setChromaQpAdj (Int idx, UChar val) { m_ChromaQpAdj[idx] = val; } + Void setChromaQpAdjSubParts( UChar val, Int absPartIdx, Int depth ); + Void setCodedChromaQpAdj ( Char qp ) { m_codedChromaQpAdj = qp; } + Char getCodedChromaQpAdj () { return m_codedChromaQpAdj; } + + Bool isLosslessCoded ( UInt absPartIdx ); + + UChar* getTransformIdx () { return m_puhTrIdx; } + UChar getTransformIdx ( UInt uiIdx ) { return m_puhTrIdx[uiIdx]; } + Void setTrIdxSubParts ( UInt uiTrIdx, UInt uiAbsPartIdx, UInt uiDepth ); + + UChar* getTransformSkip ( ComponentID compID ) { return m_puhTransformSkip[compID];} + UChar getTransformSkip ( UInt uiIdx, ComponentID compID) { return m_puhTransformSkip[compID][uiIdx];} + Void setTransformSkipSubParts ( UInt useTransformSkip, ComponentID compID, UInt uiAbsPartIdx, UInt uiDepth); + Void setTransformSkipSubParts ( const UInt useTransformSkip[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth ); + + UChar* getExplicitRdpcmMode ( ComponentID component ) { return m_explicitRdpcmMode[component]; } + UChar getExplicitRdpcmMode ( ComponentID component, UInt partIdx ) {return m_explicitRdpcmMode[component][partIdx]; } + Void setExplicitRdpcmModePartRange ( UInt rdpcmMode, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ); + + Bool isRDPCMEnabled ( UInt uiAbsPartIdx ) { return getSlice()->getSPS()->getUseResidualDPCM(isIntra(uiAbsPartIdx) ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT); } + + Void setCrossComponentPredictionAlphaPartRange ( Char alphaValue, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ); + Void setTransformSkipPartRange ( UInt useTransformSkip, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ); + + UInt getQuadtreeTULog2MinSizeInCU( UInt uiIdx ); + + TComCUMvField* getCUMvField ( RefPicList e ) { return &m_acCUMvField[e]; } + + TCoeff* getCoeff (ComponentID component) { return m_pcTrCoeff[component]; } + +#if ADAPTIVE_QP_SELECTION + TCoeff* getArlCoeff ( ComponentID component ) { return m_pcArlCoeff[component]; } +#endif + Pel* getPCMSample ( ComponentID component ) { return m_pcIPCMSample[component]; } + + UChar getCbf ( UInt uiIdx, ComponentID eType ) { return m_puhCbf[eType][uiIdx]; } + UChar* getCbf ( ComponentID eType ) { return m_puhCbf[eType]; } + UChar getCbf ( UInt uiIdx, ComponentID eType, UInt uiTrDepth ) { return ( ( getCbf( uiIdx, eType ) >> uiTrDepth ) & 0x1 ); } + Void setCbf ( UInt uiIdx, ComponentID eType, UChar uh ) { m_puhCbf[eType][uiIdx] = uh; } + Void clearCbf ( UInt uiIdx, ComponentID eType, UInt uiNumParts ); + UChar getQtRootCbf ( UInt uiIdx ); + + Void setCbfSubParts ( const UInt uiCbf[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth ); + Void setCbfSubParts ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiDepth ); + Void setCbfSubParts ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + + Void setCbfPartRange ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ); + Void bitwiseOrCbfPartRange ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for coding tool information + // ------------------------------------------------------------------------------------------------------------------- + + Bool* getMergeFlag () { return m_pbMergeFlag; } + Bool getMergeFlag ( UInt uiIdx ) { return m_pbMergeFlag[uiIdx]; } + Void setMergeFlag ( UInt uiIdx, Bool b ) { m_pbMergeFlag[uiIdx] = b; } + Void setMergeFlagSubParts ( Bool bMergeFlag, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + + UChar* getMergeIndex () { return m_puhMergeIndex; } + UChar getMergeIndex ( UInt uiIdx ) { return m_puhMergeIndex[uiIdx]; } + Void setMergeIndex ( UInt uiIdx, UInt uiMergeIndex ) { m_puhMergeIndex[uiIdx] = uiMergeIndex; } + Void setMergeIndexSubParts ( UInt uiMergeIndex, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + template + Void setSubPart ( T bParameter, T* pbBaseCtu, UInt uiCUAddr, UInt uiCUDepth, UInt uiPUIdx ); + +#if AMP_MRG + Void setMergeAMP( Bool b ) { m_bIsMergeAMP = b; } + Bool getMergeAMP( ) { return m_bIsMergeAMP; } +#endif + + UChar* getIntraDir ( const ChannelType channelType ) const { return m_puhIntraDir[channelType]; } + UChar getIntraDir ( const ChannelType channelType, const UInt uiIdx ) const { return m_puhIntraDir[channelType][uiIdx]; } + + Void setIntraDirSubParts ( const ChannelType channelType, + const UInt uiDir, + const UInt uiAbsPartIdx, + const UInt uiDepth ); + + UChar* getInterDir () { return m_puhInterDir; } + UChar getInterDir ( UInt uiIdx ) { return m_puhInterDir[uiIdx]; } + Void setInterDir ( UInt uiIdx, UChar uh ) { m_puhInterDir[uiIdx] = uh; } + Void setInterDirSubParts ( UInt uiDir, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + Bool* getIPCMFlag () { return m_pbIPCMFlag; } + Bool getIPCMFlag (UInt uiIdx ) { return m_pbIPCMFlag[uiIdx]; } + Void setIPCMFlag (UInt uiIdx, Bool b ) { m_pbIPCMFlag[uiIdx] = b; } + Void setIPCMFlagSubParts (Bool bIpcmFlag, UInt uiAbsPartIdx, UInt uiDepth); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for accessing partition information + // ------------------------------------------------------------------------------------------------------------------- + + Void getPartIndexAndSize ( UInt uiPartIdx, UInt& ruiPartAddr, Int& riWidth, Int& riHeight ); + UChar getNumPartitions ( const UInt uiAbsPartIdx = 0 ); + Bool isFirstAbsZorderIdxInDepth (UInt uiAbsPartIdx, UInt uiDepth); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for motion vector + // ------------------------------------------------------------------------------------------------------------------- + + Void getMvField ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList, TComMvField& rcMvField ); + + Void fillMvpCand ( UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, Int iRefIdx, AMVPInfo* pInfo ); + Bool isDiffMER ( Int xN, Int yN, Int xP, Int yP); + Void getPartPosition ( UInt partIdx, Int& xP, Int& yP, Int& nPSW, Int& nPSH); + + Void setMVPIdx ( RefPicList eRefPicList, UInt uiIdx, Int iMVPIdx) { m_apiMVPIdx[eRefPicList][uiIdx] = iMVPIdx; } + Int getMVPIdx ( RefPicList eRefPicList, UInt uiIdx) { return m_apiMVPIdx[eRefPicList][uiIdx]; } + Char* getMVPIdx ( RefPicList eRefPicList ) { return m_apiMVPIdx[eRefPicList]; } + + Void setMVPNum ( RefPicList eRefPicList, UInt uiIdx, Int iMVPNum ) { m_apiMVPNum[eRefPicList][uiIdx] = iMVPNum; } + Int getMVPNum ( RefPicList eRefPicList, UInt uiIdx ) { return m_apiMVPNum[eRefPicList][uiIdx]; } + Char* getMVPNum ( RefPicList eRefPicList ) { return m_apiMVPNum[eRefPicList]; } + + Void setMVPIdxSubParts ( Int iMVPIdx, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + Void setMVPNumSubParts ( Int iMVPNum, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ); + + Void clipMv ( TComMv& rcMv ); + Void getMvPredLeft ( TComMv& rcMvPred ) { rcMvPred = m_cMvFieldA.getMv(); } + Void getMvPredAbove ( TComMv& rcMvPred ) { rcMvPred = m_cMvFieldB.getMv(); } + Void getMvPredAboveRight ( TComMv& rcMvPred ) { rcMvPred = m_cMvFieldC.getMv(); } + + Void compressMV (); + + // ------------------------------------------------------------------------------------------------------------------- + // utility functions for neighbouring information + // ------------------------------------------------------------------------------------------------------------------- + + TComDataCU* getCtuLeft () { return m_pCtuLeft; } + TComDataCU* getCtuAbove () { return m_pCtuAbove; } + TComDataCU* getCtuAboveLeft () { return m_pCtuAboveLeft; } + TComDataCU* getCtuAboveRight () { return m_pCtuAboveRight; } + TComDataCU* getCUColocated ( RefPicList eRefPicList ) { return m_apcCUColocated[eRefPicList]; } + Bool CUIsFromSameSlice ( const TComDataCU *pCU /* Can be NULL */) const { return ( pCU!=NULL && pCU->getSlice()->getSliceCurStartCtuTsAddr() == getSlice()->getSliceCurStartCtuTsAddr() ); } + Bool CUIsFromSameTile ( const TComDataCU *pCU /* Can be NULL */) const; + Bool CUIsFromSameSliceAndTile ( const TComDataCU *pCU /* Can be NULL */) const; + Bool CUIsFromSameSliceTileAndWavefrontRow( const TComDataCU *pCU /* Can be NULL */) const; + Bool isLastSubCUOfCtu(const UInt absPartIdx); + + + TComDataCU* getPULeft ( UInt& uiLPartUnitIdx, + UInt uiCurrPartUnitIdx, + Bool bEnforceSliceRestriction=true, + Bool bEnforceTileRestriction=true ); + TComDataCU* getPUAbove ( UInt& uiAPartUnitIdx, + UInt uiCurrPartUnitIdx, + Bool bEnforceSliceRestriction=true, + Bool planarAtCTUBoundary = false, + Bool bEnforceTileRestriction=true ); + TComDataCU* getPUAboveLeft ( UInt& uiALPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction=true ); + TComDataCU* getPUAboveRight ( UInt& uiARPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction=true ); + TComDataCU* getPUBelowLeft ( UInt& uiBLPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction=true ); + + TComDataCU* getQpMinCuLeft ( UInt& uiLPartUnitIdx , UInt uiCurrAbsIdxInCtu ); + TComDataCU* getQpMinCuAbove ( UInt& uiAPartUnitIdx , UInt uiCurrAbsIdxInCtu ); + Char getRefQP ( UInt uiCurrAbsIdxInCtu ); + + TComDataCU* getPUAboveRightAdi ( UInt& uiARPartUnitIdx, UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset = 1, Bool bEnforceSliceRestriction=true ); + TComDataCU* getPUBelowLeftAdi ( UInt& uiBLPartUnitIdx, UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset = 1, Bool bEnforceSliceRestriction=true ); + + Void deriveLeftRightTopIdx ( UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT ); + Void deriveLeftBottomIdx ( UInt uiPartIdx, UInt& ruiPartIdxLB ); + + Void deriveLeftRightTopIdxAdi ( UInt& ruiPartIdxLT, UInt& ruiPartIdxRT, UInt uiPartOffset, UInt uiPartDepth ); + Void deriveLeftBottomIdxAdi ( UInt& ruiPartIdxLB, UInt uiPartOffset, UInt uiPartDepth ); // NOTE: Unused function. + + Bool hasEqualMotion ( UInt uiAbsPartIdx, TComDataCU* pcCandCU, UInt uiCandAbsPartIdx ); + Void getInterMergeCandidates ( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx = -1 ); + + Void deriveLeftRightTopIdxGeneral ( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT ); + Void deriveLeftBottomIdxGeneral ( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLB ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for modes + // ------------------------------------------------------------------------------------------------------------------- + + Bool isIntra ( UInt uiPartIdx ) const { return m_pePredMode[ uiPartIdx ] == MODE_INTRA; } + Bool isInter ( UInt uiPartIdx ) const { return m_pePredMode[ uiPartIdx ] == MODE_INTER; } + Bool isSkipped ( UInt uiPartIdx ); ///< SKIP (no residual) + Bool isBipredRestriction( UInt puIdx ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for symbol prediction (most probable / mode conversion) + // ------------------------------------------------------------------------------------------------------------------- + + UInt getIntraSizeIdx ( UInt uiAbsPartIdx ); + + Void getAllowedChromaDir ( UInt uiAbsPartIdx, UInt* uiModeList ); + Int getIntraDirPredictor ( UInt uiAbsPartIdx, Int uiIntraDirPred[NUM_MOST_PROBABLE_MODES], const ComponentID compID, Int* piMode = NULL ); + + // ------------------------------------------------------------------------------------------------------------------- + // member functions for SBAC context + // ------------------------------------------------------------------------------------------------------------------- + + UInt getCtxSplitFlag ( UInt uiAbsPartIdx, UInt uiDepth ); + UInt getCtxQtCbf ( TComTU &rTu, const ChannelType chType ); + + UInt getCtxSkipFlag ( UInt uiAbsPartIdx ); + UInt getCtxInterDir ( UInt uiAbsPartIdx ); + + UInt& getTotalBins () { return m_uiTotalBins; } + // ------------------------------------------------------------------------------------------------------------------- + // member functions for RD cost storage + // ------------------------------------------------------------------------------------------------------------------- + + Double& getTotalCost() { return m_dTotalCost; } + Distortion& getTotalDistortion() { return m_uiTotalDistortion; } + UInt& getTotalBits() { return m_uiTotalBits; } + UInt& getTotalNumPart() { return m_uiNumPartition; } + + UInt getCoefScanIdx(const UInt uiAbsPartIdx, const UInt uiWidth, const UInt uiHeight, const ComponentID compID) const ; + +}; + +namespace RasterAddress +{ + /** Check whether 2 addresses point to the same column + * \param addrA First address in raster scan order + * \param addrB Second address in raters scan order + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool isEqualCol( Int addrA, Int addrB, Int numUnitsPerRow ) + { + // addrA % numUnitsPerRow == addrB % numUnitsPerRow + return (( addrA ^ addrB ) & ( numUnitsPerRow - 1 ) ) == 0; + } + + /** Check whether 2 addresses point to the same row + * \param addrA First address in raster scan order + * \param addrB Second address in raters scan order + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool isEqualRow( Int addrA, Int addrB, Int numUnitsPerRow ) + { + // addrA / numUnitsPerRow == addrB / numUnitsPerRow + return (( addrA ^ addrB ) &~ ( numUnitsPerRow - 1 ) ) == 0; + } + + /** Check whether 2 addresses point to the same row or column + * \param addrA First address in raster scan order + * \param addrB Second address in raters scan order + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool isEqualRowOrCol( Int addrA, Int addrB, Int numUnitsPerRow ) + { + return isEqualCol( addrA, addrB, numUnitsPerRow ) | isEqualRow( addrA, addrB, numUnitsPerRow ); + } + + /** Check whether one address points to the first column + * \param addr Address in raster scan order + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool isZeroCol( Int addr, Int numUnitsPerRow ) + { + // addr % numUnitsPerRow == 0 + return ( addr & ( numUnitsPerRow - 1 ) ) == 0; + } + + /** Check whether one address points to the first row + * \param addr Address in raster scan order + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool isZeroRow( Int addr, Int numUnitsPerRow ) + { + // addr / numUnitsPerRow == 0 + return ( addr &~ ( numUnitsPerRow - 1 ) ) == 0; + } + + /** Check whether one address points to a column whose index is smaller than a given value + * \param addr Address in raster scan order + * \param val Given column index value + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool lessThanCol( Int addr, Int val, Int numUnitsPerRow ) + { + // addr % numUnitsPerRow < val + return ( addr & ( numUnitsPerRow - 1 ) ) < val; + } + + /** Check whether one address points to a row whose index is smaller than a given value + * \param addr Address in raster scan order + * \param val Given row index value + * \param numUnitsPerRow Number of units in a row + * \return Result of test + */ + static inline Bool lessThanRow( Int addr, Int val, Int numUnitsPerRow ) + { + // addr / numUnitsPerRow < val + return addr < val * numUnitsPerRow; + } +} + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComInterpolationFilter.cpp b/jctvc/TLibCommon/TComInterpolationFilter.cpp new file mode 100644 index 0000000..fc751d8 --- /dev/null +++ b/jctvc/TLibCommon/TComInterpolationFilter.cpp @@ -0,0 +1,383 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * \brief Implementation of TComInterpolationFilter class + */ + +// ==================================================================================================================== +// Includes +// ==================================================================================================================== + +#include "TComRom.h" +#include "TComInterpolationFilter.h" +#include + +#include "TComChromaFormat.h" + + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Tables +// ==================================================================================================================== + +const TFilterCoeff TComInterpolationFilter::m_lumaFilter[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_LUMA] = +{ + { 0, 0, 0, 64, 0, 0, 0, 0 }, + { -1, 4, -10, 58, 17, -5, 1, 0 }, + { -1, 4, -11, 40, 40, -11, 4, -1 }, + { 0, 1, -5, 17, 58, -10, 4, -1 } +}; + +const TFilterCoeff TComInterpolationFilter::m_chromaFilter[CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_CHROMA] = +{ + { 0, 64, 0, 0 }, + { -2, 58, 10, -2 }, + { -4, 54, 16, -2 }, + { -6, 46, 28, -4 }, + { -4, 36, 36, -4 }, + { -4, 28, 46, -6 }, + { -2, 16, 54, -4 }, + { -2, 10, 58, -2 } +}; + +// ==================================================================================================================== +// Private member functions +// ==================================================================================================================== + +/** + * \brief Apply unit FIR filter to a block of samples + * + * \param bitDepth bitDepth of samples + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param isFirst Flag indicating whether it is the first filtering operation + * \param isLast Flag indicating whether it is the last filtering operation + */ +Void TComInterpolationFilter::filterCopy(Int bitDepth, const Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isFirst, Bool isLast) +{ + Int row, col; + + if ( isFirst == isLast ) + { + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + dst[col] = src[col]; + } + + src += srcStride; + dst += dstStride; + } + } + else if ( isFirst ) + { + const Int shift = std::max(2, (IF_INTERNAL_PREC - bitDepth)); + + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + Pel val = leftShift_round(src[col], shift); + dst[col] = val - (Pel)IF_INTERNAL_OFFS; + } + + src += srcStride; + dst += dstStride; + } + } + else + { + const Int shift = std::max(2, (IF_INTERNAL_PREC - bitDepth)); + + Pel maxVal = (1 << bitDepth) - 1; + Pel minVal = 0; + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + Pel val = src[ col ]; + val = rightShift_round((val + IF_INTERNAL_OFFS), shift); + if (val < minVal) val = minVal; + if (val > maxVal) val = maxVal; + dst[col] = val; + } + + src += srcStride; + dst += dstStride; + } + } +} + +/** + * \brief Apply FIR filter to a block of samples + * + * \tparam N Number of taps + * \tparam isVertical Flag indicating filtering along vertical direction + * \tparam isFirst Flag indicating whether it is the first filtering operation + * \tparam isLast Flag indicating whether it is the last filtering operation + * \param bitDepth Bit depth of samples + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param coeff Pointer to filter taps + */ +template +Void TComInterpolationFilter::filter(Int bitDepth, Pel const *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, TFilterCoeff const *coeff) +{ + Int row, col; + + Pel c[8]; + c[0] = coeff[0]; + c[1] = coeff[1]; + if ( N >= 4 ) + { + c[2] = coeff[2]; + c[3] = coeff[3]; + } + if ( N >= 6 ) + { + c[4] = coeff[4]; + c[5] = coeff[5]; + } + if ( N == 8 ) + { + c[6] = coeff[6]; + c[7] = coeff[7]; + } + + Int cStride = ( isVertical ) ? srcStride : 1; + src -= ( N/2 - 1 ) * cStride; + + Int offset; + Pel maxVal; + Int headRoom = std::max(2, (IF_INTERNAL_PREC - bitDepth)); + Int shift = IF_FILTER_PREC; + // with the current settings (IF_INTERNAL_PREC = 14 and IF_FILTER_PREC = 6), though headroom can be + // negative for bit depths greater than 14, shift will remain non-negative for bit depths of 8->20 + assert(shift >= 0); + + if ( isLast ) + { + shift += (isFirst) ? 0 : headRoom; + offset = 1 << (shift - 1); + offset += (isFirst) ? 0 : IF_INTERNAL_OFFS << IF_FILTER_PREC; + maxVal = (1 << bitDepth) - 1; + } + else + { + shift -= (isFirst) ? headRoom : 0; + offset = (isFirst) ? -IF_INTERNAL_OFFS << shift : 0; + maxVal = 0; + } + + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + Int sum; + + sum = src[ col + 0 * cStride] * c[0]; + sum += src[ col + 1 * cStride] * c[1]; + if ( N >= 4 ) + { + sum += src[ col + 2 * cStride] * c[2]; + sum += src[ col + 3 * cStride] * c[3]; + } + if ( N >= 6 ) + { + sum += src[ col + 4 * cStride] * c[4]; + sum += src[ col + 5 * cStride] * c[5]; + } + if ( N == 8 ) + { + sum += src[ col + 6 * cStride] * c[6]; + sum += src[ col + 7 * cStride] * c[7]; + } + + Pel val = ( sum + offset ) >> shift; + if ( isLast ) + { + val = ( val < 0 ) ? 0 : val; + val = ( val > maxVal ) ? maxVal : val; + } + dst[col] = val; + } + + src += srcStride; + dst += dstStride; + } +} + +/** + * \brief Filter a block of samples (horizontal) + * + * \tparam N Number of taps + * \param bitDepth Bit depth of samples + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param isLast Flag indicating whether it is the last filtering operation + * \param coeff Pointer to filter taps + */ +template +Void TComInterpolationFilter::filterHor(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isLast, TFilterCoeff const *coeff) +{ + if ( isLast ) + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } + else + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } +} + +/** + * \brief Filter a block of samples (vertical) + * + * \tparam N Number of taps + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param isFirst Flag indicating whether it is the first filtering operation + * \param isLast Flag indicating whether it is the last filtering operation + * \param coeff Pointer to filter taps + */ +template +Void TComInterpolationFilter::filterVer(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isFirst, Bool isLast, TFilterCoeff const *coeff) +{ + if ( isFirst && isLast ) + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } + else if ( isFirst && !isLast ) + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } + else if ( !isFirst && isLast ) + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } + else + { + filter(bitDepth, src, srcStride, dst, dstStride, width, height, coeff); + } +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** + * \brief Filter a block of Luma/Chroma samples (horizontal) + * + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param frac Fractional sample offset + * \param isLast Flag indicating whether it is the last filtering operation + */ +Void TComInterpolationFilter::filterHor(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isLast, const ChromaFormat fmt ) +{ + if ( frac == 0 ) + { + filterCopy(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, true, isLast ); + } + else if (isLuma(compID)) + { + assert(frac >= 0 && frac < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS); + filterHor(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, isLast, m_lumaFilter[frac]); + } + else + { + const UInt csx = getComponentScaleX(compID, fmt); + assert(frac >=0 && csx<2 && (frac<<(1-csx)) < CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS); + filterHor(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, isLast, m_chromaFilter[frac<<(1-csx)]); + } +} + + +/** + * \brief Filter a block of Luma/Chroma samples (vertical) + * + * \param src Pointer to source samples + * \param srcStride Stride of source samples + * \param dst Pointer to destination samples + * \param dstStride Stride of destination samples + * \param width Width of block + * \param height Height of block + * \param frac Fractional sample offset + * \param isFirst Flag indicating whether it is the first filtering operation + * \param isLast Flag indicating whether it is the last filtering operation + */ +Void TComInterpolationFilter::filterVer(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isFirst, Bool isLast, const ChromaFormat fmt ) +{ + if ( frac == 0 ) + { + filterCopy(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, isFirst, isLast ); + } + else if (isLuma(compID)) + { + assert(frac >= 0 && frac < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS); + filterVer(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_lumaFilter[frac]); + } + else + { + const UInt csy = getComponentScaleY(compID, fmt); + assert(frac >=0 && csy<2 && (frac<<(1-csy)) < CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS); + filterVer(g_bitDepth[toChannelType(compID)], src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_chromaFilter[frac<<(1-csy)]); + } +} + +//! \} diff --git a/jctvc/TLibCommon/TComInterpolationFilter.h b/jctvc/TLibCommon/TComInterpolationFilter.h new file mode 100644 index 0000000..ba14a01 --- /dev/null +++ b/jctvc/TLibCommon/TComInterpolationFilter.h @@ -0,0 +1,81 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * \brief Declaration of TComInterpolationFilter class + */ + +#ifndef __TCOMINTERPOLATIONFILTER__ +#define __TCOMINTERPOLATIONFILTER__ + +#include "TypeDef.h" + +//! \ingroup TLibCommon +//! \{ + +#define NTAPS_LUMA 8 ///< Number of taps for luma +#define NTAPS_CHROMA 4 ///< Number of taps for chroma +#define IF_INTERNAL_PREC 14 ///< Number of bits for internal precision +#define IF_FILTER_PREC 6 ///< Log2 of sum of filter taps +#define IF_INTERNAL_OFFS (1<<(IF_INTERNAL_PREC-1)) ///< Offset used internally + +/** + * \brief Interpolation filter class + */ +class TComInterpolationFilter +{ + static const TFilterCoeff m_lumaFilter[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_LUMA]; ///< Luma filter taps + static const TFilterCoeff m_chromaFilter[CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_CHROMA]; ///< Chroma filter taps + + static Void filterCopy(Int bitDepth, const Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isFirst, Bool isLast); + + template + static Void filter(Int bitDepth, Pel const *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, TFilterCoeff const *coeff); + + template + static Void filterHor(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isLast, TFilterCoeff const *coeff); + template + static Void filterVer(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isFirst, Bool isLast, TFilterCoeff const *coeff); + +public: + TComInterpolationFilter() {} + ~TComInterpolationFilter() {} + + Void filterHor(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isLast, const ChromaFormat fmt ); + Void filterVer(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isFirst, Bool isLast, const ChromaFormat fmt ); +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComList.h b/jctvc/TLibCommon/TComList.h new file mode 100644 index 0000000..b0977c5 --- /dev/null +++ b/jctvc/TLibCommon/TComList.h @@ -0,0 +1,115 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComList.h + \brief general list class (header) +*/ + +#ifndef __TCOMLIST__ +#define __TCOMLIST__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include +#include "CommonDef.h" + +#include +using namespace std; + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// list template +template< class C > +class TComList : public std::list< C > // NOTE: should not inherit from STL classes +{ +public: + typedef typename std::list::iterator TComIterator; + + TComList& operator += ( const TComList& rcTComList) + { + if( ! rcTComList.empty() ) + { + insert( this->end(), rcTComList.begin(), rcTComList.end()); + } + return *this; + } // leszek + + C popBack() + { + C cT = this->back(); + this->pop_back(); + return cT; + } + + C popFront() + { + C cT = this->front(); + this->pop_front(); + return cT; + } + + Void pushBack( const C& rcT ) + { + /*assert( sizeof(C) == 4);*/ + if( rcT != NULL ) + { + this->push_back( rcT); + } + } + + Void pushFront( const C& rcT ) + { + /*assert( sizeof(C) == 4);*/ + if( rcT != NULL ) + { + this->push_front( rcT); + } + } + + TComIterator find( const C& rcT ) // leszek + { + return std::list< C >::find( this->begin(), this->end(), rcT ); + } +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComLoopFilter.cpp b/jctvc/TLibCommon/TComLoopFilter.cpp new file mode 100644 index 0000000..3038080 --- /dev/null +++ b/jctvc/TLibCommon/TComLoopFilter.cpp @@ -0,0 +1,923 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComLoopFilter.cpp + \brief deblocking filter +*/ + +#include "TComLoopFilter.h" +#include "TComSlice.h" +#include "TComMv.h" +#include "TComTU.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +//#define EDGE_VER 0 +//#define EDGE_HOR 1 + +#define DEFAULT_INTRA_TC_OFFSET 2 ///< Default intra TC offset + +// ==================================================================================================================== +// Tables +// ==================================================================================================================== + +const UChar TComLoopFilter::sm_tcTable[MAX_QP + 1 + DEFAULT_INTRA_TC_OFFSET] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,10,11,13,14,16,18,20,22,24 +}; + +const UChar TComLoopFilter::sm_betaTable[MAX_QP + 1] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64 +}; + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TComLoopFilter::TComLoopFilter() +: m_uiNumPartitions(0) +, m_bLFCrossTileBoundary(true) +{ + for( Int edgeDir = 0; edgeDir < NUM_EDGE_DIR; edgeDir++ ) + { + m_aapucBS [edgeDir] = NULL; + m_aapbEdgeFilter[edgeDir] = NULL; + } +} + +TComLoopFilter::~TComLoopFilter() +{ +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== +Void TComLoopFilter::setCfg( Bool bLFCrossTileBoundary ) +{ + m_bLFCrossTileBoundary = bLFCrossTileBoundary; +} + +Void TComLoopFilter::create( UInt uiMaxCUDepth ) +{ + destroy(); + m_uiNumPartitions = 1 << ( uiMaxCUDepth<<1 ); + for( Int edgeDir = 0; edgeDir < NUM_EDGE_DIR; edgeDir++ ) + { + m_aapucBS [edgeDir] = new UChar[m_uiNumPartitions]; + m_aapbEdgeFilter[edgeDir] = new Bool [m_uiNumPartitions]; + } +} + +Void TComLoopFilter::destroy() +{ + for( Int edgeDir = 0; edgeDir < NUM_EDGE_DIR; edgeDir++ ) + { + if (m_aapucBS[edgeDir] != NULL) + { + delete [] m_aapucBS[edgeDir]; + m_aapucBS[edgeDir] = NULL; + } + + if (m_aapbEdgeFilter[edgeDir]) + { + delete [] m_aapbEdgeFilter[edgeDir]; + m_aapbEdgeFilter[edgeDir] = NULL; + } + } +} + +/** + - call deblocking function for every CU + . + \param pcPic picture class (TComPic) pointer + */ +Void TComLoopFilter::loopFilterPic( TComPic* pcPic ) +{ + // Horizontal filtering + for ( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame(); ctuRsAddr++ ) + { + TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); + + ::memset( m_aapucBS [EDGE_VER], 0, sizeof( UChar ) * m_uiNumPartitions ); + ::memset( m_aapbEdgeFilter[EDGE_VER], 0, sizeof( Bool ) * m_uiNumPartitions ); + + // CU-based deblocking + xDeblockCU( pCtu, 0, 0, EDGE_VER ); + } + + // Vertical filtering + for ( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame(); ctuRsAddr++ ) + { + TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); + + ::memset( m_aapucBS [EDGE_HOR], 0, sizeof( UChar ) * m_uiNumPartitions ); + ::memset( m_aapbEdgeFilter[EDGE_HOR], 0, sizeof( Bool ) * m_uiNumPartitions ); + + // CU-based deblocking + xDeblockCU( pCtu, 0, 0, EDGE_HOR ); + } +} + + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + +/** + - Deblocking filter process in CU-based (the same function as conventional's) + . + \param Edge the direction of the edge in block boundary (horizonta/vertical), which is added newly +*/ +Void TComLoopFilter::xDeblockCU( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir ) +{ + if(pcCU->getPic()==0||pcCU->getPartitionSize(uiAbsZorderIdx)==NUMBER_OF_PART_SIZES) + { + return; + } + TComPic* pcPic = pcCU->getPic(); + UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1); + UInt uiQNumParts = uiCurNumParts>>2; + + if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth ) + { + for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts ) + { + UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ]; + UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ]; + if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) ) + { + xDeblockCU( pcCU, uiAbsZorderIdx, uiDepth+1, edgeDir ); + } + } + return; + } + + xSetLoopfilterParam( pcCU, uiAbsZorderIdx ); + TComTURecurse tuRecurse(pcCU, uiAbsZorderIdx); + xSetEdgefilterTU ( tuRecurse ); + xSetEdgefilterPU ( pcCU, uiAbsZorderIdx ); + + for( UInt uiPartIdx = uiAbsZorderIdx; uiPartIdx < uiAbsZorderIdx + uiCurNumParts; uiPartIdx++ ) + { + UInt uiBSCheck; + if( (g_uiMaxCUWidth >> g_uiMaxCUDepth) == 4 ) + { + uiBSCheck = (edgeDir == EDGE_VER && uiPartIdx%2 == 0) || (edgeDir == EDGE_HOR && (uiPartIdx-((uiPartIdx>>2)<<2))/2 == 0); + } + else + { + uiBSCheck = 1; + } + + if ( m_aapbEdgeFilter[edgeDir][uiPartIdx] && uiBSCheck ) + { + xGetBoundaryStrengthSingle ( pcCU, edgeDir, uiPartIdx ); + } + } + + UInt uiPelsInPart = g_uiMaxCUWidth >> g_uiMaxCUDepth; + UInt PartIdxIncr = DEBLOCK_SMALLEST_BLOCK / uiPelsInPart ? DEBLOCK_SMALLEST_BLOCK / uiPelsInPart : 1 ; + + UInt uiSizeInPU = pcPic->getNumPartInCtuWidth()>>(uiDepth); + const ChromaFormat chFmt=pcPic->getChromaFormat(); + const UInt shiftFactor = edgeDir == EDGE_VER ? pcPic->getComponentScaleX(COMPONENT_Cb) : pcPic->getComponentScaleY(COMPONENT_Cb); + const Bool bAlwaysDoChroma=chFmt==CHROMA_444; + + for ( Int iEdge = 0; iEdge < uiSizeInPU ; iEdge+=PartIdxIncr) + { + xEdgeFilterLuma ( pcCU, uiAbsZorderIdx, uiDepth, edgeDir, iEdge ); + if ( chFmt!=CHROMA_400 && (bAlwaysDoChroma || + (uiPelsInPart>DEBLOCK_SMALLEST_BLOCK) || + (iEdge % ( (DEBLOCK_SMALLEST_BLOCK<getPic()->getNumPartInCtuWidth () >> uiDepth; + } + if ( uiHeightInBaseUnits == 0 ) + { + uiHeightInBaseUnits = pcCU->getPic()->getNumPartInCtuHeight() >> uiDepth; + } + const UInt uiNumElem = edgeDir == EDGE_VER ? uiHeightInBaseUnits : uiWidthInBaseUnits; + assert( uiNumElem > 0 ); + assert( uiWidthInBaseUnits > 0 ); + assert( uiHeightInBaseUnits > 0 ); + for( UInt ui = 0; ui < uiNumElem; ui++ ) + { + const UInt uiBsIdx = xCalcBsIdx( pcCU, uiAbsZorderIdx, edgeDir, iEdgeIdx, ui, rect ); + m_aapbEdgeFilter[edgeDir][uiBsIdx] = bValue; + if (iEdgeIdx == 0) + { + m_aapucBS[edgeDir][uiBsIdx] = bValue; + } + } +} + +Void TComLoopFilter::xSetEdgefilterTU( TComTU &rTu ) +{ + TComDataCU* pcCU = rTu.getCU(); + UInt uiTransDepthTotal = rTu.GetTransformDepthTotal(); + + if( pcCU->getTransformIdx( rTu.GetAbsPartIdxTU() ) + pcCU->getDepth( rTu.GetAbsPartIdxTU()) > uiTransDepthTotal ) + { + TComTURecurse tuChild(rTu, false); + do + { + xSetEdgefilterTU( tuChild ); + } while (tuChild.nextSection(rTu)); + return; + } + + const TComRectangle &rect = rTu.getRect(COMPONENT_Y); + + const UInt uiWidthInBaseUnits = rect.width / (g_uiMaxCUWidth >> g_uiMaxCUDepth); + const UInt uiHeightInBaseUnits = rect.height / (g_uiMaxCUWidth >> g_uiMaxCUDepth); + + xSetEdgefilterMultiple( pcCU, rTu.GetAbsPartIdxCU(), uiTransDepthTotal, EDGE_VER, 0, m_stLFCUParam.bInternalEdge, uiWidthInBaseUnits, uiHeightInBaseUnits, &rect ); + xSetEdgefilterMultiple( pcCU, rTu.GetAbsPartIdxCU(), uiTransDepthTotal, EDGE_HOR, 0, m_stLFCUParam.bInternalEdge, uiWidthInBaseUnits, uiHeightInBaseUnits, &rect ); +} + +Void TComLoopFilter::xSetEdgefilterPU( TComDataCU* pcCU, UInt uiAbsZorderIdx ) +{ + const UInt uiDepth = pcCU->getDepth( uiAbsZorderIdx ); + const UInt uiWidthInBaseUnits = pcCU->getPic()->getNumPartInCtuWidth () >> uiDepth; + const UInt uiHeightInBaseUnits = pcCU->getPic()->getNumPartInCtuHeight() >> uiDepth; + const UInt uiHWidthInBaseUnits = uiWidthInBaseUnits >> 1; + const UInt uiHHeightInBaseUnits = uiHeightInBaseUnits >> 1; + const UInt uiQWidthInBaseUnits = uiWidthInBaseUnits >> 2; + const UInt uiQHeightInBaseUnits = uiHeightInBaseUnits >> 2; + + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_VER, 0, m_stLFCUParam.bLeftEdge ); + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_HOR, 0, m_stLFCUParam.bTopEdge ); + + switch ( pcCU->getPartitionSize( uiAbsZorderIdx ) ) + { + case SIZE_2Nx2N: + { + break; + } + case SIZE_2NxN: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_HOR, uiHHeightInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_Nx2N: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_VER, uiHWidthInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_NxN: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_VER, uiHWidthInBaseUnits, m_stLFCUParam.bInternalEdge ); + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_HOR, uiHHeightInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_2NxnU: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_HOR, uiQHeightInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_2NxnD: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_HOR, uiHeightInBaseUnits - uiQHeightInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_nLx2N: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_VER, uiQWidthInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + case SIZE_nRx2N: + { + xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, uiDepth, EDGE_VER, uiWidthInBaseUnits - uiQWidthInBaseUnits, m_stLFCUParam.bInternalEdge ); + break; + } + default: + { + break; + } + } +} + + +Void TComLoopFilter::xSetLoopfilterParam( TComDataCU* pcCU, UInt uiAbsZorderIdx ) +{ + UInt uiX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[ uiAbsZorderIdx ] ]; + UInt uiY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[ uiAbsZorderIdx ] ]; + + TComDataCU* pcTempCU; + UInt uiTempPartIdx; + + m_stLFCUParam.bInternalEdge = ! pcCU->getSlice()->getDeblockingFilterDisable(); + + if ( (uiX == 0) || pcCU->getSlice()->getDeblockingFilterDisable() ) + { + m_stLFCUParam.bLeftEdge = false; + } + else + { + m_stLFCUParam.bLeftEdge = true; + } + if ( m_stLFCUParam.bLeftEdge ) + { + pcTempCU = pcCU->getPULeft( uiTempPartIdx, uiAbsZorderIdx, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), !m_bLFCrossTileBoundary); + + if ( pcTempCU != NULL ) + { + m_stLFCUParam.bLeftEdge = true; + } + else + { + m_stLFCUParam.bLeftEdge = false; + } + } + + if ( (uiY == 0 ) || pcCU->getSlice()->getDeblockingFilterDisable() ) + { + m_stLFCUParam.bTopEdge = false; + } + else + { + m_stLFCUParam.bTopEdge = true; + } + if ( m_stLFCUParam.bTopEdge ) + { + pcTempCU = pcCU->getPUAbove( uiTempPartIdx, uiAbsZorderIdx, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary); + + if ( pcTempCU != NULL ) + { + m_stLFCUParam.bTopEdge = true; + } + else + { + m_stLFCUParam.bTopEdge = false; + } + } +} + +Void TComLoopFilter::xGetBoundaryStrengthSingle ( TComDataCU* pCtu, DeblockEdgeDir edgeDir, UInt uiAbsPartIdx4x4BlockWithinCtu ) +{ + TComSlice * const pcSlice = pCtu->getSlice(); + + const Bool lfCrossSliceBoundaryFlag=pCtu->getSlice()->getLFCrossSliceBoundaryFlag(); + + const UInt uiPartQ = uiAbsPartIdx4x4BlockWithinCtu; + TComDataCU* const pcCUQ = pCtu; + + UInt uiPartP; + TComDataCU* pcCUP; + UInt uiBs = 0; + + //-- Calculate Block Index + if (edgeDir == EDGE_VER) + { + pcCUP = pcCUQ->getPULeft(uiPartP, uiPartQ, !lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary); + } + else // (edgeDir == EDGE_HOR) + { + pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pCtu->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary); + } + + //-- Set BS for Intra MB : BS = 4 or 3 + if ( pcCUP->isIntra(uiPartP) || pcCUQ->isIntra(uiPartQ) ) + { + uiBs = 2; + } + + //-- Set BS for not Intra MB : BS = 2 or 1 or 0 + if ( !pcCUP->isIntra(uiPartP) && !pcCUQ->isIntra(uiPartQ) ) + { + UInt nsPartQ = uiPartQ; + UInt nsPartP = uiPartP; + + if ( m_aapucBS[edgeDir][uiAbsPartIdx4x4BlockWithinCtu] && (pcCUQ->getCbf( nsPartQ, COMPONENT_Y, pcCUQ->getTransformIdx(nsPartQ)) != 0 || pcCUP->getCbf( nsPartP, COMPONENT_Y, pcCUP->getTransformIdx(nsPartP) ) != 0) ) + { + uiBs = 1; + } + else + { + if (edgeDir == EDGE_HOR) + { + pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pCtu->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary); + } + if (pcSlice->isInterB() || pcCUP->getSlice()->isInterB()) + { + Int iRefIdx; + TComPic *piRefP0, *piRefP1, *piRefQ0, *piRefQ1; + iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP); + piRefP0 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx); + iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartP); + piRefP1 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_1, iRefIdx); + iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ); + piRefQ0 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx); + iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartQ); + piRefQ1 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx); + + TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP); + TComMv pcMvP1 = pcCUP->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartP); + TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ); + TComMv pcMvQ1 = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartQ); + + if (piRefP0 == NULL) pcMvP0.setZero(); + if (piRefP1 == NULL) pcMvP1.setZero(); + if (piRefQ0 == NULL) pcMvQ0.setZero(); + if (piRefQ1 == NULL) pcMvQ1.setZero(); + + if ( ((piRefP0==piRefQ0)&&(piRefP1==piRefQ1)) || ((piRefP0==piRefQ1)&&(piRefP1==piRefQ0)) ) + { + if ( piRefP0 != piRefP1 ) // Different L0 & L1 + { + if ( piRefP0 == piRefQ0 ) + { + uiBs = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) || + (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4) || + (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= 4) || + (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0; + } + else + { + uiBs = ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= 4) || + (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= 4) || + (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= 4) || + (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0; + } + } + else // Same L0 & L1 + { + uiBs = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) || + (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4) || + (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= 4) || + (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= 4)) && + ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= 4) || + (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= 4) || + (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= 4) || + (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0; + } + } + else // for all different Ref_Idx + { + uiBs = 1; + } + } + else // pcSlice->isInterP() + { + Int iRefIdx; + TComPic *piRefP0, *piRefQ0; + iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP); + piRefP0 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx); + iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ); + piRefQ0 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx); + TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP); + TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ); + + if (piRefP0 == NULL) pcMvP0.setZero(); + if (piRefQ0 == NULL) pcMvQ0.setZero(); + + uiBs = ((piRefP0 != piRefQ0) || + (abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) || + (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4)) ? 1 : 0; + } + } // enf of "if( one of BCBP == 0 )" + } // enf of "if( not Intra )" + + m_aapucBS[edgeDir][uiAbsPartIdx4x4BlockWithinCtu] = uiBs; +} + + +Void TComLoopFilter::xEdgeFilterLuma( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir, Int iEdge ) +{ + TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec(); + Pel* piSrc = pcPicYuvRec->getAddr(COMPONENT_Y, pcCU->getCtuRsAddr(), uiAbsZorderIdx ); + Pel* piTmpSrc = piSrc; + + const Bool lfCrossSliceBoundaryFlag=pcCU->getSlice()->getLFCrossSliceBoundaryFlag(); + + Int iStride = pcPicYuvRec->getStride(COMPONENT_Y); + Int iQP = 0; + Int iQP_P = 0; + Int iQP_Q = 0; + UInt uiNumParts = pcCU->getPic()->getNumPartInCtuWidth()>>uiDepth; + + UInt uiPelsInPart = g_uiMaxCUWidth >> g_uiMaxCUDepth; + UInt uiBsAbsIdx = 0, uiBs = 0; + Int iOffset, iSrcStep; + + Bool bPCMFilter = (pcCU->getSlice()->getSPS()->getUsePCM() && pcCU->getSlice()->getSPS()->getPCMFilterDisableFlag())? true : false; + Bool bPartPNoFilter = false; + Bool bPartQNoFilter = false; + UInt uiPartPIdx = 0; + UInt uiPartQIdx = 0; + TComDataCU* pcCUP = pcCU; + TComDataCU* pcCUQ = pcCU; + Int betaOffsetDiv2 = pcCUQ->getSlice()->getDeblockingFilterBetaOffsetDiv2(); + Int tcOffsetDiv2 = pcCUQ->getSlice()->getDeblockingFilterTcOffsetDiv2(); + + if (edgeDir == EDGE_VER) + { + iOffset = 1; + iSrcStep = iStride; + piTmpSrc += iEdge*uiPelsInPart; + } + else // (edgeDir == EDGE_HOR) + { + iOffset = iStride; + iSrcStep = 1; + piTmpSrc += iEdge*uiPelsInPart*iStride; + } + + for ( UInt iIdx = 0; iIdx < uiNumParts; iIdx++ ) + { + uiBsAbsIdx = xCalcBsIdx( pcCU, uiAbsZorderIdx, edgeDir, iEdge, iIdx); + uiBs = m_aapucBS[edgeDir][uiBsAbsIdx]; + if ( uiBs ) + { + iQP_Q = pcCU->getQP( uiBsAbsIdx ); + uiPartQIdx = uiBsAbsIdx; + // Derive neighboring PU index + if (edgeDir == EDGE_VER) + { + pcCUP = pcCUQ->getPULeft (uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary); + } + else // (iDir == EDGE_HOR) + { + pcCUP = pcCUQ->getPUAbove(uiPartPIdx, uiPartQIdx,!pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary); + } + + iQP_P = pcCUP->getQP(uiPartPIdx); + iQP = (iQP_P + iQP_Q + 1) >> 1; + Int iBitdepthScale = 1 << (g_bitDepth[CHANNEL_TYPE_LUMA]-8); + + Int iIndexTC = Clip3(0, MAX_QP+DEFAULT_INTRA_TC_OFFSET, Int(iQP + DEFAULT_INTRA_TC_OFFSET*(uiBs-1) + (tcOffsetDiv2 << 1))); + Int iIndexB = Clip3(0, MAX_QP, iQP + (betaOffsetDiv2 << 1)); + + Int iTc = sm_tcTable[iIndexTC]*iBitdepthScale; + Int iBeta = sm_betaTable[iIndexB]*iBitdepthScale; + Int iSideThreshold = (iBeta+(iBeta>>1))>>3; + Int iThrCut = iTc*10; + + + UInt uiBlocksInPart = uiPelsInPart / 4 ? uiPelsInPart / 4 : 1; + for (UInt iBlkIdx = 0; iBlkIdxgetSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + // Check if each of PUs is I_PCM with LF disabling + bPartPNoFilter = (bPCMFilter && pcCUP->getIPCMFlag(uiPartPIdx)); + bPartQNoFilter = (bPCMFilter && pcCUQ->getIPCMFlag(uiPartQIdx)); + + // check if each of PUs is lossless coded + bPartPNoFilter = bPartPNoFilter || (pcCUP->isLosslessCoded(uiPartPIdx) ); + bPartQNoFilter = bPartQNoFilter || (pcCUQ->isLosslessCoded(uiPartQIdx) ); + } + + if (d < iBeta) + { + Bool bFilterP = (dp < iSideThreshold); + Bool bFilterQ = (dq < iSideThreshold); + + Bool sw = xUseStrongFiltering( iOffset, 2*d0, iBeta, iTc, piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+0)) + && xUseStrongFiltering( iOffset, 2*d3, iBeta, iTc, piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+3)); + + for ( Int i = 0; i < DEBLOCK_SMALLEST_BLOCK/2; i++) + { + xPelFilterLuma( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+i), iOffset, iTc, sw, bPartPNoFilter, bPartQNoFilter, iThrCut, bFilterP, bFilterQ); + } + } + } + } + } +} + + +Void TComLoopFilter::xEdgeFilterChroma( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir, Int iEdge ) +{ + TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec(); + Int iStride = pcPicYuvRec->getStride(COMPONENT_Cb); + Pel* piSrcCb = pcPicYuvRec->getAddr( COMPONENT_Cb, pcCU->getCtuRsAddr(), uiAbsZorderIdx ); + Pel* piSrcCr = pcPicYuvRec->getAddr( COMPONENT_Cr, pcCU->getCtuRsAddr(), uiAbsZorderIdx ); + Int iQP = 0; + Int iQP_P = 0; + Int iQP_Q = 0; + + UInt uiPelsInPartChromaH = g_uiMaxCUWidth >> (g_uiMaxCUDepth+pcPicYuvRec->getComponentScaleX(COMPONENT_Cb)); + UInt uiPelsInPartChromaV = g_uiMaxCUWidth >> (g_uiMaxCUDepth+pcPicYuvRec->getComponentScaleY(COMPONENT_Cb)); + + Int iOffset, iSrcStep; + UInt uiLoopLength; + + const UInt uiCtuWidthInBaseUnits = pcCU->getPic()->getNumPartInCtuWidth(); + + Bool bPCMFilter = (pcCU->getSlice()->getSPS()->getUsePCM() && pcCU->getSlice()->getSPS()->getPCMFilterDisableFlag())? true : false; + Bool bPartPNoFilter = false; + Bool bPartQNoFilter = false; + TComDataCU* pcCUQ = pcCU; + Int tcOffsetDiv2 = pcCU->getSlice()->getDeblockingFilterTcOffsetDiv2(); + + // Vertical Position + UInt uiEdgeNumInCtuVert = g_auiZscanToRaster[uiAbsZorderIdx]%uiCtuWidthInBaseUnits + iEdge; + UInt uiEdgeNumInCtuHor = g_auiZscanToRaster[uiAbsZorderIdx]/uiCtuWidthInBaseUnits + iEdge; + + if ( (uiPelsInPartChromaH < DEBLOCK_SMALLEST_BLOCK) && (uiPelsInPartChromaV < DEBLOCK_SMALLEST_BLOCK) && + ( + ( (uiEdgeNumInCtuVert%(DEBLOCK_SMALLEST_BLOCK/uiPelsInPartChromaH)) && (edgeDir==EDGE_VER) ) || + ( (uiEdgeNumInCtuHor %(DEBLOCK_SMALLEST_BLOCK/uiPelsInPartChromaV)) && (edgeDir==EDGE_HOR) ) + ) + ) + { + return; + } + + + const Bool lfCrossSliceBoundaryFlag=pcCU->getSlice()->getLFCrossSliceBoundaryFlag(); + + UInt uiNumParts = pcCU->getPic()->getNumPartInCtuWidth()>>uiDepth; + + UInt uiBsAbsIdx; + UChar ucBs; + + Pel* piTmpSrcCb = piSrcCb; + Pel* piTmpSrcCr = piSrcCr; + + if (edgeDir == EDGE_VER) + { + iOffset = 1; + iSrcStep = iStride; + piTmpSrcCb += iEdge*uiPelsInPartChromaH; + piTmpSrcCr += iEdge*uiPelsInPartChromaH; + uiLoopLength=uiPelsInPartChromaV; + } + else // (edgeDir == EDGE_HOR) + { + iOffset = iStride; + iSrcStep = 1; + piTmpSrcCb += iEdge*iStride*uiPelsInPartChromaV; + piTmpSrcCr += iEdge*iStride*uiPelsInPartChromaV; + uiLoopLength=uiPelsInPartChromaH; + } + + for ( UInt iIdx = 0; iIdx < uiNumParts; iIdx++ ) + { + uiBsAbsIdx = xCalcBsIdx( pcCU, uiAbsZorderIdx, edgeDir, iEdge, iIdx); + ucBs = m_aapucBS[edgeDir][uiBsAbsIdx]; + + if ( ucBs > 1) + { + iQP_Q = pcCU->getQP( uiBsAbsIdx ); + UInt uiPartQIdx = uiBsAbsIdx; + // Derive neighboring PU index + TComDataCU* pcCUP; + UInt uiPartPIdx; + + if (edgeDir == EDGE_VER) + { + pcCUP = pcCUQ->getPULeft (uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary); + } + else // (edgeDir == EDGE_HOR) + { + pcCUP = pcCUQ->getPUAbove(uiPartPIdx, uiPartQIdx,!pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary); + } + + iQP_P = pcCUP->getQP(uiPartPIdx); + + if (bPCMFilter || pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + // Check if each of PUs is I_PCM with LF disabling + bPartPNoFilter = (bPCMFilter && pcCUP->getIPCMFlag(uiPartPIdx)); + bPartQNoFilter = (bPCMFilter && pcCUQ->getIPCMFlag(uiPartQIdx)); + + // check if each of PUs is lossless coded + bPartPNoFilter = bPartPNoFilter || (pcCUP->isLosslessCoded(uiPartPIdx)); + bPartQNoFilter = bPartQNoFilter || (pcCUQ->isLosslessCoded(uiPartQIdx)); + } + + for ( UInt chromaIdx = 0; chromaIdx < 2; chromaIdx++ ) + { + Int chromaQPOffset = pcCU->getSlice()->getPPS()->getQpOffset(ComponentID(chromaIdx + 1)); + Pel* piTmpSrcChroma = (chromaIdx == 0) ? piTmpSrcCb : piTmpSrcCr; + + iQP = ((iQP_P + iQP_Q + 1) >> 1) + chromaQPOffset; + if (iQP >= chromaQPMappingTableSize) + { + if (pcPicYuvRec->getChromaFormat()==CHROMA_420) iQP -=6; + else if (iQP>51) iQP=51; + } + else if (iQP >= 0 ) + { + iQP = getScaledChromaQP(iQP, pcPicYuvRec->getChromaFormat()); + } + + Int iBitdepthScale = 1 << (g_bitDepth[CHANNEL_TYPE_CHROMA]-8); + + Int iIndexTC = Clip3(0, MAX_QP+DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET*(ucBs - 1) + (tcOffsetDiv2 << 1)); + Int iTc = sm_tcTable[iIndexTC]*iBitdepthScale; + + for ( UInt uiStep = 0; uiStep < uiLoopLength; uiStep++ ) + { + xPelFilterChroma( piTmpSrcChroma + iSrcStep*(uiStep+iIdx*uiLoopLength), iOffset, iTc , bPartPNoFilter, bPartQNoFilter); + } + } + } + } +} + +/** + - Deblocking for the luminance component with strong or weak filter + . + \param piSrc pointer to picture data + \param iOffset offset value for picture data + \param tc tc value + \param sw decision strong/weak filter + \param bPartPNoFilter indicator to disable filtering on partP + \param bPartQNoFilter indicator to disable filtering on partQ + \param iThrCut threshold value for weak filter decision + \param bFilterSecondP decision weak filter/no filter for partP + \param bFilterSecondQ decision weak filter/no filter for partQ +*/ +__inline Void TComLoopFilter::xPelFilterLuma( Pel* piSrc, Int iOffset, Int tc, Bool sw, Bool bPartPNoFilter, Bool bPartQNoFilter, Int iThrCut, Bool bFilterSecondP, Bool bFilterSecondQ) +{ + Int delta; + + Pel m4 = piSrc[0]; + Pel m3 = piSrc[-iOffset]; + Pel m5 = piSrc[ iOffset]; + Pel m2 = piSrc[-iOffset*2]; + Pel m6 = piSrc[ iOffset*2]; + Pel m1 = piSrc[-iOffset*3]; + Pel m7 = piSrc[ iOffset*3]; + Pel m0 = piSrc[-iOffset*4]; + + if (sw) + { + piSrc[-iOffset] = Clip3(m3-2*tc, m3+2*tc, ((m1 + 2*m2 + 2*m3 + 2*m4 + m5 + 4) >> 3)); + piSrc[0] = Clip3(m4-2*tc, m4+2*tc, ((m2 + 2*m3 + 2*m4 + 2*m5 + m6 + 4) >> 3)); + piSrc[-iOffset*2] = Clip3(m2-2*tc, m2+2*tc, ((m1 + m2 + m3 + m4 + 2)>>2)); + piSrc[ iOffset] = Clip3(m5-2*tc, m5+2*tc, ((m3 + m4 + m5 + m6 + 2)>>2)); + piSrc[-iOffset*3] = Clip3(m1-2*tc, m1+2*tc, ((2*m0 + 3*m1 + m2 + m3 + m4 + 4 )>>3)); + piSrc[ iOffset*2] = Clip3(m6-2*tc, m6+2*tc, ((m3 + m4 + m5 + 3*m6 + 2*m7 +4 )>>3)); + } + else + { + /* Weak filter */ + delta = (9*(m4-m3) -3*(m5-m2) + 8)>>4 ; + + if ( abs(delta) < iThrCut ) + { + delta = Clip3(-tc, tc, delta); + piSrc[-iOffset] = Clip((m3+delta), CHANNEL_TYPE_LUMA); + piSrc[0] = Clip((m4-delta), CHANNEL_TYPE_LUMA); + + Int tc2 = tc>>1; + if(bFilterSecondP) + { + Int delta1 = Clip3(-tc2, tc2, (( ((m1+m3+1)>>1)- m2+delta)>>1)); + piSrc[-iOffset*2] = Clip((m2+delta1), CHANNEL_TYPE_LUMA); + } + if(bFilterSecondQ) + { + Int delta2 = Clip3(-tc2, tc2, (( ((m6+m4+1)>>1)- m5-delta)>>1)); + piSrc[ iOffset] = Clip((m5+delta2), CHANNEL_TYPE_LUMA); + } + } + } + + if(bPartPNoFilter) + { + piSrc[-iOffset] = m3; + piSrc[-iOffset*2] = m2; + piSrc[-iOffset*3] = m1; + } + if(bPartQNoFilter) + { + piSrc[0] = m4; + piSrc[ iOffset] = m5; + piSrc[ iOffset*2] = m6; + } +} + +/** + - Deblocking of one line/column for the chrominance component + . + \param piSrc pointer to picture data + \param iOffset offset value for picture data + \param tc tc value + \param bPartPNoFilter indicator to disable filtering on partP + \param bPartQNoFilter indicator to disable filtering on partQ + */ +__inline Void TComLoopFilter::xPelFilterChroma( Pel* piSrc, Int iOffset, Int tc, Bool bPartPNoFilter, Bool bPartQNoFilter) +{ + Int delta; + + Pel m4 = piSrc[0]; + Pel m3 = piSrc[-iOffset]; + Pel m5 = piSrc[ iOffset]; + Pel m2 = piSrc[-iOffset*2]; + + delta = Clip3(-tc,tc, (((( m4 - m3 ) << 2 ) + m2 - m5 + 4 ) >> 3) ); + piSrc[-iOffset] = Clip((m3+delta), CHANNEL_TYPE_CHROMA); + piSrc[0] = Clip((m4-delta), CHANNEL_TYPE_CHROMA); + + if(bPartPNoFilter) + { + piSrc[-iOffset] = m3; + } + if(bPartQNoFilter) + { + piSrc[0] = m4; + } +} + +/** + - Decision between strong and weak filter + . + \param offset offset value for picture data + \param d d value + \param beta beta value + \param tc tc value + \param piSrc pointer to picture data + */ +__inline Bool TComLoopFilter::xUseStrongFiltering( Int offset, Int d, Int beta, Int tc, Pel* piSrc) +{ + Pel m4 = piSrc[0]; + Pel m3 = piSrc[-offset]; + Pel m7 = piSrc[ offset*3]; + Pel m0 = piSrc[-offset*4]; + + Int d_strong = abs(m0-m3) + abs(m7-m4); + + return ( (d_strong < (beta>>3)) && (d<(beta>>2)) && ( abs(m3-m4) < ((tc*5+1)>>1)) ); +} + +__inline Int TComLoopFilter::xCalcDP( Pel* piSrc, Int iOffset) +{ + return abs( piSrc[-iOffset*3] - 2*piSrc[-iOffset*2] + piSrc[-iOffset] ) ; +} + +__inline Int TComLoopFilter::xCalcDQ( Pel* piSrc, Int iOffset) +{ + return abs( piSrc[0] - 2*piSrc[iOffset] + piSrc[iOffset*2] ); +} +//! \} diff --git a/jctvc/TLibCommon/TComLoopFilter.h b/jctvc/TLibCommon/TComLoopFilter.h new file mode 100644 index 0000000..2871af8 --- /dev/null +++ b/jctvc/TLibCommon/TComLoopFilter.h @@ -0,0 +1,143 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComLoopFilter.h + \brief deblocking filter (header) +*/ + +#ifndef __TCOMLOOPFILTER__ +#define __TCOMLOOPFILTER__ + +#include "CommonDef.h" +#include "TComPic.h" + +//! \ingroup TLibCommon +//! \{ + +#define DEBLOCK_SMALLEST_BLOCK 8 + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// deblocking filter class +class TComLoopFilter +{ +private: + + UInt m_uiNumPartitions; + UChar* m_aapucBS[NUM_EDGE_DIR]; ///< Bs for [Ver/Hor][Y/U/V][Blk_Idx] + Bool* m_aapbEdgeFilter[NUM_EDGE_DIR]; + LFCUParam m_stLFCUParam; ///< status structure + + Bool m_bLFCrossTileBoundary; + +protected: + /// CU-level deblocking function + Void xDeblockCU ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir ); + + // set / get functions + Void xSetLoopfilterParam ( TComDataCU* pcCU, UInt uiAbsZorderIdx ); + // filtering functions + Void xSetEdgefilterTU ( TComTU &rTu ); + Void xSetEdgefilterPU ( TComDataCU* pcCU, UInt uiAbsZorderIdx ); + Void xGetBoundaryStrengthSingle ( TComDataCU* pCtu, DeblockEdgeDir edgeDir, UInt uiPartIdx ); + UInt xCalcBsIdx ( TComDataCU* pcCU, UInt absZIdxInCtu, DeblockEdgeDir edgeDir, Int iEdgeIdx, Int iBaseUnitIdx, const struct TComRectangle *rect=NULL ) + { + TComPic* const pcPic = pcCU->getPic(); + const UInt ctuWidthInBaseUnits = pcPic->getNumPartInCtuWidth(); + Int rasterOffsetTU=0; + if (rect != NULL) + { + const UInt minCuWidth =pcPic->getMinCUWidth(); + const UInt minCuHeight=pcPic->getMinCUHeight(); + rasterOffsetTU = rect->x0/minCuWidth + (rect->y0/minCuHeight)*ctuWidthInBaseUnits; + } + if( edgeDir == EDGE_VER ) + { + return g_auiRasterToZscan[g_auiZscanToRaster[absZIdxInCtu] + iBaseUnitIdx * ctuWidthInBaseUnits + iEdgeIdx + rasterOffsetTU ]; + } + else + { + return g_auiRasterToZscan[g_auiZscanToRaster[absZIdxInCtu] + iEdgeIdx * ctuWidthInBaseUnits + iBaseUnitIdx + rasterOffsetTU ]; + } + } + + Void xSetEdgefilterMultiple( TComDataCU* pcCU, + UInt uiAbsZorderIdx, + UInt uiDepth, + DeblockEdgeDir edgeDir, + Int iEdgeIdx, + Bool bValue, + UInt uiWidthInBaseUnits = 0, + UInt uiHeightInBaseUnits = 0, + const TComRectangle *rect = 0 + ); + + Void xEdgeFilterLuma ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir, Int iEdge ); + Void xEdgeFilterChroma ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir, Int iEdge ); + + __inline Void xPelFilterLuma( Pel* piSrc, Int iOffset, Int tc, Bool sw, Bool bPartPNoFilter, Bool bPartQNoFilter, Int iThrCut, Bool bFilterSecondP, Bool bFilterSecondQ); + __inline Void xPelFilterChroma( Pel* piSrc, Int iOffset, Int tc, Bool bPartPNoFilter, Bool bPartQNoFilter); + + + __inline Bool xUseStrongFiltering( Int offset, Int d, Int beta, Int tc, Pel* piSrc); + __inline Int xCalcDP( Pel* piSrc, Int iOffset); + __inline Int xCalcDQ( Pel* piSrc, Int iOffset); + + static const UChar sm_tcTable[54]; + static const UChar sm_betaTable[52]; + +public: + TComLoopFilter(); + virtual ~TComLoopFilter(); + + Void create ( UInt uiMaxCUDepth ); + Void destroy (); + + /// set configuration + Void setCfg( Bool bLFCrossTileBoundary ); + + /// picture-level deblocking filter + Void loopFilterPic( TComPic* pcPic ); + + static Int getBeta( Int qp ) + { + Int indexB = Clip3( 0, MAX_QP, qp ); + return sm_betaTable[ indexB ]; + } +}; + +//! \} + +#endif diff --git a/jctvc/TLibCommon/TComMotionInfo.cpp b/jctvc/TLibCommon/TComMotionInfo.cpp new file mode 100644 index 0000000..250c399 --- /dev/null +++ b/jctvc/TLibCommon/TComMotionInfo.cpp @@ -0,0 +1,351 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComMotionInfo.cpp + \brief motion information handling classes +*/ + +#include +#include "TComMotionInfo.h" +#include "assert.h" +#include + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +// -------------------------------------------------------------------------------------------------------------------- +// Create / destroy +// -------------------------------------------------------------------------------------------------------------------- + +Void TComCUMvField::create( UInt uiNumPartition ) +{ + assert(m_pcMv == NULL); + assert(m_pcMvd == NULL); + assert(m_piRefIdx == NULL); + + m_pcMv = new TComMv[ uiNumPartition ]; + m_pcMvd = new TComMv[ uiNumPartition ]; + m_piRefIdx = new Char [ uiNumPartition ]; + + m_uiNumPartition = uiNumPartition; +} + +Void TComCUMvField::destroy() +{ + assert(m_pcMv != NULL); + assert(m_pcMvd != NULL); + assert(m_piRefIdx != NULL); + + delete[] m_pcMv; + delete[] m_pcMvd; + delete[] m_piRefIdx; + + m_pcMv = NULL; + m_pcMvd = NULL; + m_piRefIdx = NULL; + + m_uiNumPartition = 0; +} + +// -------------------------------------------------------------------------------------------------------------------- +// Clear / copy +// -------------------------------------------------------------------------------------------------------------------- + +Void TComCUMvField::clearMvField() +{ + for ( Int i = 0; i < m_uiNumPartition; i++ ) + { + m_pcMv [ i ].setZero(); + m_pcMvd[ i ].setZero(); + } + assert( sizeof( *m_piRefIdx ) == 1 ); + memset( m_piRefIdx, NOT_VALID, m_uiNumPartition * sizeof( *m_piRefIdx ) ); +} + +Void TComCUMvField::copyFrom( TComCUMvField const * pcCUMvFieldSrc, Int iNumPartSrc, Int iPartAddrDst ) +{ + Int iSizeInTComMv = sizeof( TComMv ) * iNumPartSrc; + + memcpy( m_pcMv + iPartAddrDst, pcCUMvFieldSrc->m_pcMv, iSizeInTComMv ); + memcpy( m_pcMvd + iPartAddrDst, pcCUMvFieldSrc->m_pcMvd, iSizeInTComMv ); + memcpy( m_piRefIdx + iPartAddrDst, pcCUMvFieldSrc->m_piRefIdx, sizeof( *m_piRefIdx ) * iNumPartSrc ); +} + +Void TComCUMvField::copyTo( TComCUMvField* pcCUMvFieldDst, Int iPartAddrDst ) const +{ + copyTo( pcCUMvFieldDst, iPartAddrDst, 0, m_uiNumPartition ); +} + +Void TComCUMvField::copyTo( TComCUMvField* pcCUMvFieldDst, Int iPartAddrDst, UInt uiOffset, UInt uiNumPart ) const +{ + Int iSizeInTComMv = sizeof( TComMv ) * uiNumPart; + Int iOffset = uiOffset + iPartAddrDst; + + memcpy( pcCUMvFieldDst->m_pcMv + iOffset, m_pcMv + uiOffset, iSizeInTComMv ); + memcpy( pcCUMvFieldDst->m_pcMvd + iOffset, m_pcMvd + uiOffset, iSizeInTComMv ); + memcpy( pcCUMvFieldDst->m_piRefIdx + iOffset, m_piRefIdx + uiOffset, sizeof( *m_piRefIdx ) * uiNumPart ); +} + +// -------------------------------------------------------------------------------------------------------------------- +// Set +// -------------------------------------------------------------------------------------------------------------------- + +template +Void TComCUMvField::setAll( T *p, T const & val, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ) +{ + Int i; + p += iPartAddr; + Int numElements = m_uiNumPartition >> ( 2 * uiDepth ); + + switch( eCUMode ) + { + case SIZE_2Nx2N: + for ( i = 0; i < numElements; i++ ) + { + p[ i ] = val; + } + break; + + case SIZE_2NxN: + numElements >>= 1; + for ( i = 0; i < numElements; i++ ) + { + p[ i ] = val; + } + break; + + case SIZE_Nx2N: + numElements >>= 2; + for ( i = 0; i < numElements; i++ ) + { + p[ i ] = val; + p[ i + 2 * numElements ] = val; + } + break; + + case SIZE_NxN: + numElements >>= 2; + for ( i = 0; i < numElements; i++) + { + p[ i ] = val; + } + break; + case SIZE_2NxnU: + { + Int iCurrPartNumQ = numElements>>2; + if( iPartIdx == 0 ) + { + T *pT = p; + T *pT2 = p + iCurrPartNumQ; + for (i = 0; i < (iCurrPartNumQ>>1); i++) + { + pT [i] = val; + pT2[i] = val; + } + } + else + { + T *pT = p; + for (i = 0; i < (iCurrPartNumQ>>1); i++) + { + pT[i] = val; + } + + pT = p + iCurrPartNumQ; + for (i = 0; i < ( (iCurrPartNumQ>>1) + (iCurrPartNumQ<<1) ); i++) + { + pT[i] = val; + } + } + break; + } + case SIZE_2NxnD: + { + Int iCurrPartNumQ = numElements>>2; + if( iPartIdx == 0 ) + { + T *pT = p; + for (i = 0; i < ( (iCurrPartNumQ>>1) + (iCurrPartNumQ<<1) ); i++) + { + pT[i] = val; + } + pT = p + ( numElements - iCurrPartNumQ ); + for (i = 0; i < (iCurrPartNumQ>>1); i++) + { + pT[i] = val; + } + } + else + { + T *pT = p; + T *pT2 = p + iCurrPartNumQ; + for (i = 0; i < (iCurrPartNumQ>>1); i++) + { + pT [i] = val; + pT2[i] = val; + } + } + break; + } + case SIZE_nLx2N: + { + Int iCurrPartNumQ = numElements>>2; + if( iPartIdx == 0 ) + { + T *pT = p; + T *pT2 = p + (iCurrPartNumQ<<1); + T *pT3 = p + (iCurrPartNumQ>>1); + T *pT4 = p + (iCurrPartNumQ<<1) + (iCurrPartNumQ>>1); + + for (i = 0; i < (iCurrPartNumQ>>2); i++) + { + pT [i] = val; + pT2[i] = val; + pT3[i] = val; + pT4[i] = val; + } + } + else + { + T *pT = p; + T *pT2 = p + (iCurrPartNumQ<<1); + for (i = 0; i < (iCurrPartNumQ>>2); i++) + { + pT [i] = val; + pT2[i] = val; + } + + pT = p + (iCurrPartNumQ>>1); + pT2 = p + (iCurrPartNumQ<<1) + (iCurrPartNumQ>>1); + for (i = 0; i < ( (iCurrPartNumQ>>2) + iCurrPartNumQ ); i++) + { + pT [i] = val; + pT2[i] = val; + } + } + break; + } + case SIZE_nRx2N: + { + Int iCurrPartNumQ = numElements>>2; + if( iPartIdx == 0 ) + { + T *pT = p; + T *pT2 = p + (iCurrPartNumQ<<1); + for (i = 0; i < ( (iCurrPartNumQ>>2) + iCurrPartNumQ ); i++) + { + pT [i] = val; + pT2[i] = val; + } + + pT = p + iCurrPartNumQ + (iCurrPartNumQ>>1); + pT2 = p + numElements - iCurrPartNumQ + (iCurrPartNumQ>>1); + for (i = 0; i < (iCurrPartNumQ>>2); i++) + { + pT [i] = val; + pT2[i] = val; + } + } + else + { + T *pT = p; + T *pT2 = p + (iCurrPartNumQ>>1); + T *pT3 = p + (iCurrPartNumQ<<1); + T *pT4 = p + (iCurrPartNumQ<<1) + (iCurrPartNumQ>>1); + for (i = 0; i < (iCurrPartNumQ>>2); i++) + { + pT [i] = val; + pT2[i] = val; + pT3[i] = val; + pT4[i] = val; + } + } + break; + } + default: + assert(0); + break; + } +} + +Void TComCUMvField::setAllMv( TComMv const & mv, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ) +{ + setAll(m_pcMv, mv, eCUMode, iPartAddr, uiDepth, iPartIdx); +} + +Void TComCUMvField::setAllMvd( TComMv const & mvd, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ) +{ + setAll(m_pcMvd, mvd, eCUMode, iPartAddr, uiDepth, iPartIdx); +} + +Void TComCUMvField::setAllRefIdx ( Int iRefIdx, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ) +{ + setAll(m_piRefIdx, static_cast(iRefIdx), eCUMode, iPartAddr, uiDepth, iPartIdx); +} + +Void TComCUMvField::setAllMvField( TComMvField const & mvField, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ) +{ + setAllMv ( mvField.getMv(), eCUMode, iPartAddr, uiDepth, iPartIdx ); + setAllRefIdx( mvField.getRefIdx(), eCUMode, iPartAddr, uiDepth, iPartIdx ); +} + +/**Subsampling of the stored prediction mode, reference index and motion vector + * \param pePredMode Pointer to prediction modes + * \param scale Factor by which to subsample motion information + */ +Void TComCUMvField::compress(Char* pePredMode, Int scale) +{ + Int N = scale * scale; + assert( N > 0 && N <= m_uiNumPartition); + + for ( Int uiPartIdx = 0; uiPartIdx < m_uiNumPartition; uiPartIdx += N ) + { + TComMv cMv(0,0); + Int iRefIdx = 0; + + cMv = m_pcMv[ uiPartIdx ]; + PredMode predMode = static_cast( pePredMode[ uiPartIdx ] ); + iRefIdx = m_piRefIdx[ uiPartIdx ]; + for ( Int i = 0; i < N; i++ ) + { + m_pcMv[ uiPartIdx + i ] = cMv; + pePredMode[ uiPartIdx + i ] = predMode; + m_piRefIdx[ uiPartIdx + i ] = iRefIdx; + } + } +} +//! \} diff --git a/jctvc/TLibCommon/TComMotionInfo.h b/jctvc/TLibCommon/TComMotionInfo.h new file mode 100644 index 0000000..a76175e --- /dev/null +++ b/jctvc/TLibCommon/TComMotionInfo.h @@ -0,0 +1,160 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComMotionInfo.h + \brief motion information handling classes (header) + \todo TComMvField seems to be better to be inherited from TComMv +*/ + +#ifndef __TCOMMOTIONINFO__ +#define __TCOMMOTIONINFO__ + +#include +#include "CommonDef.h" +#include "TComMv.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Type definition +// ==================================================================================================================== + +/// parameters for AMVP +typedef struct _AMVPInfo +{ + TComMv m_acMvCand[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of motion vector predictor candidates + Int iN; ///< number of motion vector predictor candidates +} AMVPInfo; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// class for motion vector with reference index +class TComMvField +{ +private: + TComMv m_acMv; + Int m_iRefIdx; + +public: + TComMvField() : m_iRefIdx( NOT_VALID ) {} + + Void setMvField( TComMv const & cMv, Int iRefIdx ) + { + m_acMv = cMv; + m_iRefIdx = iRefIdx; + } + + Void setRefIdx( Int refIdx ) { m_iRefIdx = refIdx; } + + TComMv const & getMv() const { return m_acMv; } + TComMv & getMv() { return m_acMv; } + + Int getRefIdx() const { return m_iRefIdx; } + Int getHor () const { return m_acMv.getHor(); } + Int getVer () const { return m_acMv.getVer(); } +}; + +/// class for motion information in one CU +class TComCUMvField +{ +private: + TComMv* m_pcMv; + TComMv* m_pcMvd; + Char* m_piRefIdx; + UInt m_uiNumPartition; + AMVPInfo m_cAMVPInfo; + + template + Void setAll( T *p, T const & val, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx ); + +public: + TComCUMvField() : m_pcMv(NULL), m_pcMvd(NULL), m_piRefIdx(NULL), m_uiNumPartition(0) {} + ~TComCUMvField() {} + + // ------------------------------------------------------------------------------------------------------------------ + // create / destroy + // ------------------------------------------------------------------------------------------------------------------ + + Void create( UInt uiNumPartition ); + Void destroy(); + + // ------------------------------------------------------------------------------------------------------------------ + // clear / copy + // ------------------------------------------------------------------------------------------------------------------ + + Void clearMvField(); + + Void copyFrom( TComCUMvField const * pcCUMvFieldSrc, Int iNumPartSrc, Int iPartAddrDst ); + Void copyTo ( TComCUMvField* pcCUMvFieldDst, Int iPartAddrDst ) const; + Void copyTo ( TComCUMvField* pcCUMvFieldDst, Int iPartAddrDst, UInt uiOffset, UInt uiNumPart ) const; + + // ------------------------------------------------------------------------------------------------------------------ + // get + // ------------------------------------------------------------------------------------------------------------------ + + TComMv const & getMv ( Int iIdx ) const { return m_pcMv [iIdx]; } + TComMv const & getMvd ( Int iIdx ) const { return m_pcMvd [iIdx]; } + Int getRefIdx( Int iIdx ) const { return m_piRefIdx[iIdx]; } + + AMVPInfo* getAMVPInfo () { return &m_cAMVPInfo; } + + // ------------------------------------------------------------------------------------------------------------------ + // set + // ------------------------------------------------------------------------------------------------------------------ + + Void setAllMv ( TComMv const & rcMv, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx=0 ); + Void setAllMvd ( TComMv const & rcMvd, PartSize eCUMode, Int iPartAddr, UInt uiDepth, Int iPartIdx=0 ); + Void setAllRefIdx ( Int iRefIdx, PartSize eMbMode, Int iPartAddr, UInt uiDepth, Int iPartIdx=0 ); + Void setAllMvField( TComMvField const & mvField, PartSize eMbMode, Int iPartAddr, UInt uiDepth, Int iPartIdx=0 ); + + Void setNumPartition( Int iNumPart ) + { + m_uiNumPartition = iNumPart; + } + + Void linkToWithOffset( TComCUMvField const * src, Int offset ) + { + m_pcMv = src->m_pcMv + offset; + m_pcMvd = src->m_pcMvd + offset; + m_piRefIdx = src->m_piRefIdx + offset; + } + + Void compress(Char* pePredMode, Int scale); +}; + +//! \} + +#endif // __TCOMMOTIONINFO__ diff --git a/jctvc/TLibCommon/TComMv.h b/jctvc/TLibCommon/TComMv.h new file mode 100644 index 0000000..ab0102a --- /dev/null +++ b/jctvc/TLibCommon/TComMv.h @@ -0,0 +1,156 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComMv.h + \brief motion vector class (header) +*/ + +#ifndef __TCOMMV__ +#define __TCOMMV__ + +#include "CommonDef.h" +#include + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// basic motion vector class +class TComMv +{ +private: + Short m_iHor; ///< horizontal component of motion vector + Short m_iVer; ///< vertical component of motion vector + +public: + + // ------------------------------------------------------------------------------------------------------------------ + // constructors + // ------------------------------------------------------------------------------------------------------------------ + + TComMv() : + m_iHor(0), + m_iVer(0) + { + } + + TComMv( Short iHor, Short iVer ) : + m_iHor(iHor), + m_iVer(iVer) + { + } + + // ------------------------------------------------------------------------------------------------------------------ + // set + // ------------------------------------------------------------------------------------------------------------------ + + Void set ( Short iHor, Short iVer) { m_iHor = iHor; m_iVer = iVer; } + Void setHor ( Short i ) { m_iHor = i; } + Void setVer ( Short i ) { m_iVer = i; } + Void setZero () { m_iHor = m_iVer = 0; } + + // ------------------------------------------------------------------------------------------------------------------ + // get + // ------------------------------------------------------------------------------------------------------------------ + + Int getHor () const { return m_iHor; } + Int getVer () const { return m_iVer; } + Int getAbsHor () const { return abs( m_iHor ); } + Int getAbsVer () const { return abs( m_iVer ); } + + // ------------------------------------------------------------------------------------------------------------------ + // operations + // ------------------------------------------------------------------------------------------------------------------ + + const TComMv& operator += (const TComMv& rcMv) + { + m_iHor += rcMv.m_iHor; + m_iVer += rcMv.m_iVer; + return *this; + } + + const TComMv& operator-= (const TComMv& rcMv) + { + m_iHor -= rcMv.m_iHor; + m_iVer -= rcMv.m_iVer; + return *this; + } + + const TComMv& operator>>= (const Int i) + { + m_iHor >>= i; + m_iVer >>= i; + return *this; + } + + const TComMv& operator<<= (const Int i) + { + m_iHor <<= i; + m_iVer <<= i; + return *this; + } + + const TComMv operator - ( const TComMv& rcMv ) const + { + return TComMv( m_iHor - rcMv.m_iHor, m_iVer - rcMv.m_iVer ); + } + + const TComMv operator + ( const TComMv& rcMv ) const + { + return TComMv( m_iHor + rcMv.m_iHor, m_iVer + rcMv.m_iVer ); + } + + Bool operator== ( const TComMv& rcMv ) const + { + return (m_iHor==rcMv.m_iHor && m_iVer==rcMv.m_iVer); + } + + Bool operator!= ( const TComMv& rcMv ) const + { + return (m_iHor!=rcMv.m_iHor || m_iVer!=rcMv.m_iVer); + } + + const TComMv scaleMv( Int iScale ) const + { + Int mvx = Clip3( -32768, 32767, (iScale * getHor() + 127 + (iScale * getHor() < 0)) >> 8 ); + Int mvy = Clip3( -32768, 32767, (iScale * getVer() + 127 + (iScale * getVer() < 0)) >> 8 ); + return TComMv( mvx, mvy ); + } +};// END CLASS DEFINITION TComMV + +//! \} + +#endif // __TCOMMV__ diff --git a/jctvc/TLibCommon/TComPattern.cpp b/jctvc/TLibCommon/TComPattern.cpp new file mode 100644 index 0000000..7c5654d --- /dev/null +++ b/jctvc/TLibCommon/TComPattern.cpp @@ -0,0 +1,734 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPattern.cpp + \brief neighbouring pixel access classes +*/ + +#include "TComPic.h" +#include "TComPattern.h" +#include "TComDataCU.h" +#include "TComTU.h" +#include "Debug.h" +#include "TComPrediction.h" + +//! \ingroup TLibCommon +//! \{ + +// Forward declarations + +/// padding of unavailable reference samples for intra prediction +#if O0043_BEST_EFFORT_DECODING +Void fillReferenceSamples( const Int bitDepth, const Int bitDepthDelta, TComDataCU* pcCU, const Pel* piRoiOrigin, Pel* piAdiTemp, const Bool* bNeighborFlags, +#else +Void fillReferenceSamples( const Int bitDepth, TComDataCU* pcCU, const Pel* piRoiOrigin, Pel* piAdiTemp, const Bool* bNeighborFlags, +#endif + const Int iNumIntraNeighbor, const Int unitWidth, const Int unitHeight, const Int iAboveUnits, const Int iLeftUnits, + const UInt uiCuWidth, const UInt uiCuHeight, const UInt uiWidth, const UInt uiHeight, const Int iPicStride, + const ChannelType chType, const ChromaFormat chFmt ); + +/// constrained intra prediction +Bool isAboveLeftAvailable ( TComDataCU* pcCU, UInt uiPartIdxLT ); +Int isAboveAvailable ( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxRT, Bool* bValidFlags ); +Int isLeftAvailable ( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxLB, Bool* bValidFlags ); +Int isAboveRightAvailable ( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxRT, Bool* bValidFlags ); +Int isBelowLeftAvailable ( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxLB, Bool* bValidFlags ); + + +// ==================================================================================================================== +// Public member functions (TComPatternParam) +// ==================================================================================================================== + +/** \param piTexture pixel data + \param iRoiWidth pattern width + \param iRoiHeight pattern height + \param iStride buffer stride + \param iOffsetLeft neighbour offset (left) + \param iOffsetRight neighbour offset (right) + \param iOffsetAbove neighbour offset (above) + \param iOffsetBottom neighbour offset (bottom) + */ +Void TComPatternParam::setPatternParamPel ( Pel* piTexture, + Int iRoiWidth, + Int iRoiHeight, + Int iStride + ) +{ + m_piROIOrigin = piTexture; + m_iROIWidth = iRoiWidth; + m_iROIHeight = iRoiHeight; + m_iPatternStride = iStride; +} + +// ==================================================================================================================== +// Public member functions (TComPattern) +// ==================================================================================================================== + +Void TComPattern::initPattern (Pel* piY, + Int iRoiWidth, + Int iRoiHeight, + Int iStride) +{ + m_cPatternY. setPatternParamPel( piY, iRoiWidth, iRoiHeight, iStride); +} + + +// TODO: move this function to TComPrediction.cpp. +Void TComPrediction::initAdiPatternChType( TComTU &rTu, Bool& bAbove, Bool& bLeft, const ComponentID compID, const Bool bFilterRefSamples DEBUG_STRING_FN_DECLARE(sDebug)) +{ + const ChannelType chType = toChannelType(compID); + + TComDataCU *pcCU=rTu.getCU(); + const UInt uiZorderIdxInPart=rTu.GetAbsPartIdxTU(); + const UInt uiTuWidth = rTu.getRect(compID).width; + const UInt uiTuHeight = rTu.getRect(compID).height; + const UInt uiTuWidth2 = uiTuWidth << 1; + const UInt uiTuHeight2 = uiTuHeight << 1; + + const Int iBaseUnitSize = g_uiMaxCUWidth >> g_uiMaxCUDepth; + const Int iUnitWidth = iBaseUnitSize >> pcCU->getPic()->getPicYuvRec()->getComponentScaleX(compID); + const Int iUnitHeight = iBaseUnitSize >> pcCU->getPic()->getPicYuvRec()->getComponentScaleY(compID); + const Int iTUWidthInUnits = uiTuWidth / iUnitWidth; + const Int iTUHeightInUnits = uiTuHeight / iUnitHeight; + const Int iAboveUnits = iTUWidthInUnits << 1; + const Int iLeftUnits = iTUHeightInUnits << 1; + + assert(iTUHeightInUnits > 0 && iTUWidthInUnits > 0); + + const Int iPartIdxStride = pcCU->getPic()->getNumPartInCtuWidth(); + const UInt uiPartIdxLT = pcCU->getZorderIdxInCtu() + uiZorderIdxInPart; + const UInt uiPartIdxRT = g_auiRasterToZscan[ g_auiZscanToRaster[ uiPartIdxLT ] + iTUWidthInUnits - 1 ]; + const UInt uiPartIdxLB = g_auiRasterToZscan[ g_auiZscanToRaster[ uiPartIdxLT ] + ((iTUHeightInUnits - 1) * iPartIdxStride)]; + + Int iPicStride = pcCU->getPic()->getStride(compID); + Bool bNeighborFlags[4 * MAX_NUM_SPU_W + 1]; + Int iNumIntraNeighbor = 0; + + bNeighborFlags[iLeftUnits] = isAboveLeftAvailable( pcCU, uiPartIdxLT ); + iNumIntraNeighbor += bNeighborFlags[iLeftUnits] ? 1 : 0; + iNumIntraNeighbor += isAboveAvailable ( pcCU, uiPartIdxLT, uiPartIdxRT, (bNeighborFlags + iLeftUnits + 1) ); + iNumIntraNeighbor += isAboveRightAvailable( pcCU, uiPartIdxLT, uiPartIdxRT, (bNeighborFlags + iLeftUnits + 1 + iTUWidthInUnits ) ); + iNumIntraNeighbor += isLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, (bNeighborFlags + iLeftUnits - 1) ); + iNumIntraNeighbor += isBelowLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, (bNeighborFlags + iLeftUnits - 1 - iTUHeightInUnits) ); + + bAbove = true; + bLeft = true; + + const ChromaFormat chFmt = rTu.GetChromaFormat(); + const UInt uiROIWidth = uiTuWidth2+1; + const UInt uiROIHeight = uiTuHeight2+1; + + assert(uiROIWidth*uiROIHeight <= m_iYuvExtSize); + +#ifdef DEBUG_STRING + std::stringstream ss(stringstream::out); +#endif + + { + Pel *piAdiTemp = m_piYuvExt[compID][PRED_BUF_UNFILTERED]; + Pel *piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getAddr(compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu()+uiZorderIdxInPart); +#if O0043_BEST_EFFORT_DECODING + fillReferenceSamples (g_bitDepthInStream[chType], g_bitDepthInStream[chType] - g_bitDepth[chType], pcCU, piRoiOrigin, piAdiTemp, bNeighborFlags, iNumIntraNeighbor, iUnitWidth, iUnitHeight, iAboveUnits, iLeftUnits, +#else + fillReferenceSamples (g_bitDepth[chType], pcCU, piRoiOrigin, piAdiTemp, bNeighborFlags, iNumIntraNeighbor, iUnitWidth, iUnitHeight, iAboveUnits, iLeftUnits, +#endif + uiTuWidth, uiTuHeight, uiROIWidth, uiROIHeight, iPicStride, toChannelType(compID), chFmt); + + +#ifdef DEBUG_STRING + if (DebugOptionList::DebugString_Pred.getInt()&DebugStringGetPredModeMask(MODE_INTRA)) + { + ss << "###: generating Ref Samples for channel " << compID << " and " << rTu.getRect(compID).width << " x " << rTu.getRect(compID).height << "\n"; + for (UInt y=0; ygetSlice()->getSPS()->getUseStrongIntraSmoothing(); + + const Pel bottomLeft = piAdiTemp[stride * uiTuHeight2]; + const Pel topLeft = piAdiTemp[0]; + const Pel topRight = piAdiTemp[uiTuWidth2]; + + if (useStrongIntraSmoothing) + { +#if O0043_BEST_EFFORT_DECODING + const Int threshold = 1 << (g_bitDepthInStream[chType] - 5); +#else + const Int threshold = 1 << (g_bitDepth[chType] - 5); +#endif + const Bool bilinearLeft = abs((bottomLeft + topLeft ) - (2 * piAdiTemp[stride * uiTuHeight])) < threshold; //difference between the + const Bool bilinearAbove = abs((topLeft + topRight) - (2 * piAdiTemp[ uiTuWidth ])) < threshold; //ends and the middle + if ((uiTuWidth < 32) || (!bilinearLeft) || (!bilinearAbove)) + useStrongIntraSmoothing = false; + } + + *piDestPtr = *piSrcPtr; // bottom left is not filtered + piDestPtr -= stride; + piSrcPtr -= stride; + + //------------------------------------------------ + + //left column (bottom to top) + + if (useStrongIntraSmoothing) + { + const Int shift = g_aucConvertToBit[uiTuHeight] + 3; //log2(uiTuHeight2) + + for(UInt i=1; i> shift; + } + + piSrcPtr -= stride * (uiTuHeight2 - 1); + } + else + { + for(UInt i=1; i> 2; + } + } + + //------------------------------------------------ + + //top-left + + if (useStrongIntraSmoothing) + { + *piDestPtr = piSrcPtr[0]; + } + else + { + *piDestPtr = ( piSrcPtr[stride] + 2*piSrcPtr[0] + piSrcPtr[1] + 2 ) >> 2; + } + piDestPtr += 1; + piSrcPtr += 1; + + //------------------------------------------------ + + //top row (left-to-right) + + if (useStrongIntraSmoothing) + { + const Int shift = g_aucConvertToBit[uiTuWidth] + 3; //log2(uiTuWidth2) + + for(UInt i=1; i> shift; + } + + piSrcPtr += uiTuWidth2 - 1; + } + else + { + for(UInt i=1; i> 2; + } + } + + //------------------------------------------------ + + *piDestPtr=*piSrcPtr; // far right is not filtered + +#ifdef DEBUG_STRING + if (DebugOptionList::DebugString_Pred.getInt()&DebugStringGetPredModeMask(MODE_INTRA)) + { + ss << "###: filtered result for channel " << compID <<"\n"; + for (UInt y=0; y(iNext, iLeftUnits); + // fill left column + while (iCurrJnit < iNextOrTop) + { + for (i=0; i= iLeftUnits) ? unitWidth : unitHeight; + const Pel refSample = *(piAdiLineCur-1); + for (i=0; i= iLeftUnits) ? unitWidth : unitHeight; + iCurrJnit++; + } + } + + // Copy processed samples + + piAdiLineTemp = piAdiLine + uiHeight + unitWidth - 2; + // top left, top and top right samples + for (i=0; i=4 && uiTuChHeight>=4 && uiTuChWidth<128 && uiTuChHeight<128); + + if (uiDirMode == DC_IDX) + { + bFilter=false; //no smoothing for DC or LM chroma + } + else + { + Int diff = min(abs((Int) uiDirMode - HOR_IDX), abs((Int)uiDirMode - VER_IDX)); + UInt sizeIndex=g_aucConvertToBit[uiTuChWidth]; + assert(sizeIndex < MAX_INTRA_FILTER_DEPTHS); + bFilter = diff > m_aucIntraFilter[toChannelType(compID)][sizeIndex]; + } + } + return bFilter; +} + +Bool isAboveLeftAvailable( TComDataCU* pcCU, UInt uiPartIdxLT ) +{ + Bool bAboveLeftFlag; + UInt uiPartAboveLeft; + TComDataCU* pcCUAboveLeft = pcCU->getPUAboveLeft( uiPartAboveLeft, uiPartIdxLT ); + if(pcCU->getSlice()->getPPS()->getConstrainedIntraPred()) + { + bAboveLeftFlag = ( pcCUAboveLeft && pcCUAboveLeft->isIntra( uiPartAboveLeft ) ); + } + else + { + bAboveLeftFlag = (pcCUAboveLeft ? true : false); + } + return bAboveLeftFlag; +} + +Int isAboveAvailable( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxRT, Bool *bValidFlags ) +{ + const UInt uiRasterPartBegin = g_auiZscanToRaster[uiPartIdxLT]; + const UInt uiRasterPartEnd = g_auiZscanToRaster[uiPartIdxRT]+1; + const UInt uiIdxStep = 1; + Bool *pbValidFlags = bValidFlags; + Int iNumIntra = 0; + + for ( UInt uiRasterPart = uiRasterPartBegin; uiRasterPart < uiRasterPartEnd; uiRasterPart += uiIdxStep ) + { + UInt uiPartAbove; + TComDataCU* pcCUAbove = pcCU->getPUAbove( uiPartAbove, g_auiRasterToZscan[uiRasterPart] ); + if(pcCU->getSlice()->getPPS()->getConstrainedIntraPred()) + { + if ( pcCUAbove && pcCUAbove->isIntra( uiPartAbove ) ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + else + { + if (pcCUAbove) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + pbValidFlags++; + } + return iNumIntra; +} + +Int isLeftAvailable( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxLB, Bool *bValidFlags ) +{ + const UInt uiRasterPartBegin = g_auiZscanToRaster[uiPartIdxLT]; + const UInt uiRasterPartEnd = g_auiZscanToRaster[uiPartIdxLB]+1; + const UInt uiIdxStep = pcCU->getPic()->getNumPartInCtuWidth(); + Bool *pbValidFlags = bValidFlags; + Int iNumIntra = 0; + + for ( UInt uiRasterPart = uiRasterPartBegin; uiRasterPart < uiRasterPartEnd; uiRasterPart += uiIdxStep ) + { + UInt uiPartLeft; + TComDataCU* pcCULeft = pcCU->getPULeft( uiPartLeft, g_auiRasterToZscan[uiRasterPart] ); + if(pcCU->getSlice()->getPPS()->getConstrainedIntraPred()) + { + if ( pcCULeft && pcCULeft->isIntra( uiPartLeft ) ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + else + { + if ( pcCULeft ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + pbValidFlags--; // opposite direction + } + + return iNumIntra; +} + +Int isAboveRightAvailable( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxRT, Bool *bValidFlags ) +{ + const UInt uiNumUnitsInPU = g_auiZscanToRaster[uiPartIdxRT] - g_auiZscanToRaster[uiPartIdxLT] + 1; + Bool *pbValidFlags = bValidFlags; + Int iNumIntra = 0; + + for ( UInt uiOffset = 1; uiOffset <= uiNumUnitsInPU; uiOffset++ ) + { + UInt uiPartAboveRight; + TComDataCU* pcCUAboveRight = pcCU->getPUAboveRightAdi( uiPartAboveRight, uiPartIdxRT, uiOffset ); + if(pcCU->getSlice()->getPPS()->getConstrainedIntraPred()) + { + if ( pcCUAboveRight && pcCUAboveRight->isIntra( uiPartAboveRight ) ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + else + { + if ( pcCUAboveRight ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + pbValidFlags++; + } + + return iNumIntra; +} + +Int isBelowLeftAvailable( TComDataCU* pcCU, UInt uiPartIdxLT, UInt uiPartIdxLB, Bool *bValidFlags ) +{ + const UInt uiNumUnitsInPU = (g_auiZscanToRaster[uiPartIdxLB] - g_auiZscanToRaster[uiPartIdxLT]) / pcCU->getPic()->getNumPartInCtuWidth() + 1; + Bool *pbValidFlags = bValidFlags; + Int iNumIntra = 0; + + for ( UInt uiOffset = 1; uiOffset <= uiNumUnitsInPU; uiOffset++ ) + { + UInt uiPartBelowLeft; + TComDataCU* pcCUBelowLeft = pcCU->getPUBelowLeftAdi( uiPartBelowLeft, uiPartIdxLB, uiOffset ); + if(pcCU->getSlice()->getPPS()->getConstrainedIntraPred()) + { + if ( pcCUBelowLeft && pcCUBelowLeft->isIntra( uiPartBelowLeft ) ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + else + { + if ( pcCUBelowLeft ) + { + iNumIntra++; + *pbValidFlags = true; + } + else + { + *pbValidFlags = false; + } + } + pbValidFlags--; // opposite direction + } + + return iNumIntra; +} +//! \} diff --git a/jctvc/TLibCommon/TComPattern.h b/jctvc/TLibCommon/TComPattern.h new file mode 100644 index 0000000..8d304ac --- /dev/null +++ b/jctvc/TLibCommon/TComPattern.h @@ -0,0 +1,114 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPattern.h + \brief neighbouring pixel access classes (header) +*/ + +#ifndef __TCOMPATTERN__ +#define __TCOMPATTERN__ + +// Include files +#include +#include "CommonDef.h" +#include + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +class TComDataCU; +class TComTU; + +/// neighbouring pixel access class for one component +class TComPatternParam +{ +private: + Pel* m_piROIOrigin; + +public: + Int m_iROIWidth; + Int m_iROIHeight; + Int m_iPatternStride; + + /// return starting position of ROI (ROI = &pattern[AboveOffset][LeftOffset]) + __inline Pel* getROIOrigin() + { + return m_piROIOrigin; + } + + /// set parameters from Pel buffer for accessing neighbouring pixels + Void setPatternParamPel (Pel* piTexture, + Int iRoiWidth, + Int iRoiHeight, + Int iStride + ); +}; + +/// neighbouring pixel access class for all components +class TComPattern +{ +private: + TComPatternParam m_cPatternY; +// TComPatternParam m_cPatternCb; + //TComPatternParam m_cPatternCr; + +public: + + // ROI & pattern information, (ROI = &pattern[AboveOffset][LeftOffset]) + Pel* getROIY() { return m_cPatternY.getROIOrigin(); } + Int getROIYWidth() { return m_cPatternY.m_iROIWidth; } + Int getROIYHeight() { return m_cPatternY.m_iROIHeight; } + Int getPatternLStride() { return m_cPatternY.m_iPatternStride; } + + // ------------------------------------------------------------------------------------------------------------------- + // initialization functions + // ------------------------------------------------------------------------------------------------------------------- + + /// set parameters from Pel buffers for accessing neighbouring pixels + Void initPattern (Pel* piY, + Int iRoiWidth, + Int iRoiHeight, + Int iStride ); + + + + +}; + +//! \} + +#endif // __TCOMPATTERN__ diff --git a/jctvc/TLibCommon/TComPic.cpp b/jctvc/TLibCommon/TComPic.cpp new file mode 100644 index 0000000..8be0026 --- /dev/null +++ b/jctvc/TLibCommon/TComPic.cpp @@ -0,0 +1,177 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPic.cpp + \brief picture class +*/ + +#include "TComPic.h" +#include "SEI.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TComPic::TComPic() +: m_uiTLayer (0) +, m_bUsedByCurr (false) +, m_bIsLongTerm (false) +, m_apcPicSym (NULL) +, m_pcPicYuvPred (NULL) +, m_pcPicYuvResi (NULL) +, m_bReconstructed (false) +, m_bNeededForOutput (false) +, m_uiCurrSliceIdx (0) +, m_bCheckLTMSB (false) +{ + for(UInt i=0; icreate( chromaFormatIDC, iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); + if (!bIsVirtual) + { + m_apcPicYuv[PIC_YUV_ORG] = new TComPicYuv; m_apcPicYuv[PIC_YUV_ORG]->create( iWidth, iHeight, chromaFormatIDC, uiMaxWidth, uiMaxHeight, uiMaxDepth ); + m_apcPicYuv[PIC_YUV_TRUE_ORG] = new TComPicYuv; m_apcPicYuv[PIC_YUV_TRUE_ORG]->create( iWidth, iHeight, chromaFormatIDC, uiMaxWidth, uiMaxHeight, uiMaxDepth ); + } + m_apcPicYuv[PIC_YUV_REC] = new TComPicYuv; m_apcPicYuv[PIC_YUV_REC]->create( iWidth, iHeight, chromaFormatIDC, uiMaxWidth, uiMaxHeight, uiMaxDepth ); + + // there are no SEI messages associated with this picture initially + if (m_SEIs.size() > 0) + { + deleteSEIs (m_SEIs); + } + m_bUsedByCurr = false; + + /* store conformance window parameters with picture */ + m_conformanceWindow = conformanceWindow; + + /* store display window parameters with picture */ + m_defaultDisplayWindow = defaultDisplayWindow; + + /* store number of reorder pics with picture */ + memcpy(m_numReorderPics, numReorderPics, MAX_TLAYER*sizeof(Int)); + + return; +} + +Void TComPic::destroy() +{ + if (m_apcPicSym) + { + m_apcPicSym->destroy(); + delete m_apcPicSym; + m_apcPicSym = NULL; + } + + for(UInt i=0; idestroy(); + delete m_apcPicYuv[i]; + m_apcPicYuv[i] = NULL; + } + } + + deleteSEIs(m_SEIs); +} + +Void TComPic::compressMotion() +{ + TComPicSym* pPicSym = getPicSym(); + for ( UInt uiCUAddr = 0; uiCUAddr < pPicSym->getNumberOfCtusInFrame(); uiCUAddr++ ) + { + TComDataCU* pCtu = pPicSym->getCtu(uiCUAddr); + pCtu->compressMV(); + } +} + +Bool TComPic::getSAOMergeAvailability(Int currAddr, Int mergeAddr) +{ + Bool mergeCtbInSliceSeg = (mergeAddr >= getPicSym()->getCtuTsToRsAddrMap(getCtu(currAddr)->getSlice()->getSliceCurStartCtuTsAddr())); + Bool mergeCtbInTile = (getPicSym()->getTileIdxMap(mergeAddr) == getPicSym()->getTileIdxMap(currAddr)); + return (mergeCtbInSliceSeg && mergeCtbInTile); +} + +UInt TComPic::getSubstreamForCtuAddr(const UInt ctuAddr, const Bool bAddressInRaster, TComSlice *pcSlice) +{ + UInt subStrm; + + if (pcSlice->getPPS()->getNumSubstreams() > 1) // wavefronts, and possibly tiles being used. + { + if (pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) + { + const TComPicSym &picSym = *(getPicSym()); + const UInt ctuRsAddr = bAddressInRaster?ctuAddr : picSym.getCtuTsToRsAddrMap(ctuAddr); + const UInt frameWidthInCtus = picSym.getFrameWidthInCtus(); + const UInt tileIndex = picSym.getTileIdxMap(ctuRsAddr); + const UInt numTileColumns = (picSym.getNumTileColumnsMinus1()+1); + const TComTile *pTile = picSym.getTComTile(tileIndex); + const UInt firstCtuRsAddrOfTile = pTile->getFirstCtuRsAddr(); + const UInt tileYInCtus = firstCtuRsAddrOfTile / frameWidthInCtus; + // independent tiles => substreams are "per tile" + const UInt ctuLine = ctuRsAddr / frameWidthInCtus; + const UInt startingSubstreamForTile =(tileYInCtus*numTileColumns) + (pTile->getTileHeightInCtus()*(tileIndex%numTileColumns)); + subStrm = startingSubstreamForTile + (ctuLine - tileYInCtus); + } + else + { + const TComPicSym &picSym = *(getPicSym()); + const UInt ctuRsAddr = bAddressInRaster?ctuAddr : picSym.getCtuTsToRsAddrMap(ctuAddr); + const UInt tileIndex = picSym.getTileIdxMap(ctuRsAddr); + subStrm=tileIndex; + } + } + else + { + // dependent tiles => substreams are "per frame". + subStrm = 0; + } + return subStrm; +} + + +//! \} diff --git a/jctvc/TLibCommon/TComPic.h b/jctvc/TLibCommon/TComPic.h new file mode 100644 index 0000000..3638c74 --- /dev/null +++ b/jctvc/TLibCommon/TComPic.h @@ -0,0 +1,181 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPic.h + \brief picture class (header) +*/ + +#ifndef __TCOMPIC__ +#define __TCOMPIC__ + +// Include files +#include "CommonDef.h" +#include "TComPicSym.h" +#include "TComPicYuv.h" +#include "TComBitStream.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// picture class (symbol + YUV buffers) + +class TComPic +{ +public: + typedef enum { PIC_YUV_ORG=0, PIC_YUV_REC=1, PIC_YUV_TRUE_ORG=2, NUM_PIC_YUV=3 } PIC_YUV_T; + // TRUE_ORG is the input file without any pre-encoder colour space conversion (but with possible bit depth increment) + TComPicYuv* getPicYuvTrueOrg() { return m_apcPicYuv[PIC_YUV_TRUE_ORG]; } + +private: + UInt m_uiTLayer; // Temporal layer + Bool m_bUsedByCurr; // Used by current picture + Bool m_bIsLongTerm; // IS long term picture + TComPicSym* m_apcPicSym; // Symbol + TComPicYuv* m_apcPicYuv[NUM_PIC_YUV]; + + TComPicYuv* m_pcPicYuvPred; // Prediction + TComPicYuv* m_pcPicYuvResi; // Residual + Bool m_bReconstructed; + Bool m_bNeededForOutput; + UInt m_uiCurrSliceIdx; // Index of current slice + Bool m_bCheckLTMSB; + + Int m_numReorderPics[MAX_TLAYER]; + Window m_conformanceWindow; + Window m_defaultDisplayWindow; + + Bool m_isTop; + Bool m_isField; + + std::vector > m_vSliceCUDataLink; + + SEIMessages m_SEIs; ///< Any SEI messages that have been received. If !NULL we own the object. + +public: + TComPic(); + virtual ~TComPic(); + + Void create( Int iWidth, Int iHeight, ChromaFormat chromaFormatIDC, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, Window &conformanceWindow, Window &defaultDisplayWindow, + Int *numReorderPics,Bool bIsVirtual /*= false*/ ); + + virtual Void destroy(); + + UInt getTLayer() const { return m_uiTLayer; } + Void setTLayer( UInt uiTLayer ) { m_uiTLayer = uiTLayer; } + + Bool getUsedByCurr() const { return m_bUsedByCurr; } + Void setUsedByCurr( Bool bUsed ) { m_bUsedByCurr = bUsed; } + Bool getIsLongTerm() const { return m_bIsLongTerm; } + Void setIsLongTerm( Bool lt ) { m_bIsLongTerm = lt; } + Void setCheckLTMSBPresent (Bool b ) {m_bCheckLTMSB=b;} + Bool getCheckLTMSBPresent () { return m_bCheckLTMSB;} + + TComPicSym* getPicSym() { return m_apcPicSym; } + TComSlice* getSlice(Int i) { return m_apcPicSym->getSlice(i); } + Int getPOC() const { return m_apcPicSym->getSlice(m_uiCurrSliceIdx)->getPOC(); } + TComDataCU* getCtu( UInt ctuRsAddr ) { return m_apcPicSym->getCtu( ctuRsAddr ); } + const TComDataCU* getCtu( UInt ctuRsAddr ) const { return m_apcPicSym->getCtu( ctuRsAddr ); } + + TComPicYuv* getPicYuvOrg() { return m_apcPicYuv[PIC_YUV_ORG]; } + TComPicYuv* getPicYuvRec() { return m_apcPicYuv[PIC_YUV_REC]; } + + TComPicYuv* getPicYuvPred() { return m_pcPicYuvPred; } + TComPicYuv* getPicYuvResi() { return m_pcPicYuvResi; } + Void setPicYuvPred( TComPicYuv* pcPicYuv ) { m_pcPicYuvPred = pcPicYuv; } + Void setPicYuvResi( TComPicYuv* pcPicYuv ) { m_pcPicYuvResi = pcPicYuv; } + + UInt getNumberOfCtusInFrame() const { return m_apcPicSym->getNumberOfCtusInFrame(); } + UInt getNumPartInCtuWidth() const { return m_apcPicSym->getNumPartInCtuWidth(); } + UInt getNumPartInCtuHeight() const { return m_apcPicSym->getNumPartInCtuHeight(); } + UInt getNumPartitionsInCtu() const { return m_apcPicSym->getNumPartitionsInCtu(); } + UInt getFrameWidthInCtus() const { return m_apcPicSym->getFrameWidthInCtus(); } + UInt getFrameHeightInCtus() const { return m_apcPicSym->getFrameHeightInCtus(); } + UInt getMinCUWidth() const { return m_apcPicSym->getMinCUWidth(); } + UInt getMinCUHeight() const { return m_apcPicSym->getMinCUHeight(); } + + Int getStride(const ComponentID id) const { return m_apcPicYuv[PIC_YUV_REC]->getStride(id); } + Int getComponentScaleX(const ComponentID id) const { return m_apcPicYuv[PIC_YUV_REC]->getComponentScaleX(id); } + Int getComponentScaleY(const ComponentID id) const { return m_apcPicYuv[PIC_YUV_REC]->getComponentScaleY(id); } + ChromaFormat getChromaFormat() const { return m_apcPicYuv[PIC_YUV_REC]->getChromaFormat(); } + Int getNumberValidComponents() const { return m_apcPicYuv[PIC_YUV_REC]->getNumberValidComponents(); } + + Void setReconMark (Bool b) { m_bReconstructed = b; } + Bool getReconMark () const { return m_bReconstructed; } + Void setOutputMark (Bool b) { m_bNeededForOutput = b; } + Bool getOutputMark () const { return m_bNeededForOutput; } + + Void setNumReorderPics(Int i, UInt tlayer) { m_numReorderPics[tlayer] = i; } + Int getNumReorderPics(UInt tlayer) { return m_numReorderPics[tlayer]; } + + Void compressMotion(); + UInt getCurrSliceIdx() const { return m_uiCurrSliceIdx; } + Void setCurrSliceIdx(UInt i) { m_uiCurrSliceIdx = i; } + UInt getNumAllocatedSlice() const {return m_apcPicSym->getNumAllocatedSlice();} + Void allocateNewSlice() {m_apcPicSym->allocateNewSlice(); } + Void clearSliceBuffer() {m_apcPicSym->clearSliceBuffer(); } + + Window& getConformanceWindow() { return m_conformanceWindow; } + Window& getDefDisplayWindow() { return m_defaultDisplayWindow; } + + Bool getSAOMergeAvailability(Int currAddr, Int mergeAddr); + + UInt getSubstreamForCtuAddr(const UInt ctuAddr, const Bool bAddressInRaster, TComSlice *pcSlice); + + /* field coding parameters*/ + + Void setTopField(Bool b) {m_isTop = b;} + Bool isTopField() {return m_isTop;} + Void setField(Bool b) {m_isField = b;} + Bool isField() {return m_isField;} + + /** transfer ownership of seis to this picture */ + Void setSEIs(SEIMessages& seis) { m_SEIs = seis; } + + /** + * return the current list of SEI messages associated with this picture. + * Pointer is valid until this->destroy() is called */ + SEIMessages& getSEIs() { return m_SEIs; } + + /** + * return the current list of SEI messages associated with this picture. + * Pointer is valid until this->destroy() is called */ + const SEIMessages& getSEIs() const { return m_SEIs; } +};// END CLASS DEFINITION TComPic + +//! \} + +#endif // __TCOMPIC__ diff --git a/jctvc/TLibCommon/TComPicSym.cpp b/jctvc/TLibCommon/TComPicSym.cpp new file mode 100644 index 0000000..71a6512 --- /dev/null +++ b/jctvc/TLibCommon/TComPicSym.cpp @@ -0,0 +1,483 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPicSym.cpp + \brief picture symbol class +*/ + +#include "TComPicSym.h" +#include "TComSampleAdaptiveOffset.h" +#include "TComSlice.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TComPicSym::TComPicSym() +:m_frameWidthInCtus(0) +,m_frameHeightInCtus(0) +,m_uiMaxCUWidth(0) +,m_uiMaxCUHeight(0) +,m_uiMinCUWidth(0) +,m_uiMinCUHeight(0) +,m_uhTotalDepth(0) +,m_numPartitionsInCtu(0) +,m_numPartInCtuWidth(0) +,m_numPartInCtuHeight(0) +,m_numCtusInFrame(0) +,m_apcTComSlice(NULL) +,m_uiNumAllocatedSlice(0) +,m_pictureCtuArray(NULL) +,m_numTileColumnsMinus1(0) +,m_numTileRowsMinus1(0) +,m_ctuTsToRsAddrMap(NULL) +,m_puiTileIdxMap(NULL) +,m_ctuRsToTsAddrMap(NULL) +,m_saoBlkParams(NULL) +{} + + +Void TComPicSym::create ( ChromaFormat chromaFormatIDC, Int iPicWidth, Int iPicHeight, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth ) +{ + UInt i; + + m_uhTotalDepth = uiMaxDepth; + m_numPartitionsInCtu = 1<<(m_uhTotalDepth<<1); + + m_uiMaxCUWidth = uiMaxWidth; + m_uiMaxCUHeight = uiMaxHeight; + + m_uiMinCUWidth = uiMaxWidth >> m_uhTotalDepth; + m_uiMinCUHeight = uiMaxHeight >> m_uhTotalDepth; + + m_numPartInCtuWidth = m_uiMaxCUWidth / m_uiMinCUWidth; // equivalent to 1<0) + { + for ( i=0; icreate( chromaFormatIDC, m_numPartitionsInCtu, m_uiMaxCUWidth, m_uiMaxCUHeight, false, m_uiMaxCUWidth >> m_uhTotalDepth +#if ADAPTIVE_QP_SELECTION + , true +#endif + ); + } + + m_ctuTsToRsAddrMap = new UInt[m_numCtusInFrame+1]; + m_puiTileIdxMap = new UInt[m_numCtusInFrame]; + m_ctuRsToTsAddrMap = new UInt[m_numCtusInFrame+1]; + + for( i=0; i0) + { + for (Int i = 0; idestroy(); + delete m_pictureCtuArray[i]; + m_pictureCtuArray[i] = NULL; + } + delete [] m_pictureCtuArray; + m_pictureCtuArray = NULL; + + delete [] m_ctuTsToRsAddrMap; + m_ctuTsToRsAddrMap = NULL; + + delete [] m_puiTileIdxMap; + m_puiTileIdxMap = NULL; + + delete [] m_ctuRsToTsAddrMap; + m_ctuRsToTsAddrMap = NULL; + + if(m_saoBlkParams) + { + delete[] m_saoBlkParams; m_saoBlkParams = NULL; + } +} + +Void TComPicSym::allocateNewSlice() +{ + assert ((m_uiNumAllocatedSlice + 1) <= m_numCtusInFrame); + m_apcTComSlice[m_uiNumAllocatedSlice ++] = new TComSlice; + if (m_uiNumAllocatedSlice>=2) + { + m_apcTComSlice[m_uiNumAllocatedSlice-1]->copySliceInfo( m_apcTComSlice[m_uiNumAllocatedSlice-2] ); + m_apcTComSlice[m_uiNumAllocatedSlice-1]->initSlice(); + } +} + +Void TComPicSym::clearSliceBuffer() +{ + UInt i; + for (i = 1; i < m_uiNumAllocatedSlice; i++) + { + delete m_apcTComSlice[i]; + } + m_uiNumAllocatedSlice = 1; +} + +Void TComPicSym::initCtuTsRsAddrMaps() +{ + //generate the Coding Order Map and Inverse Coding Order Map + for(Int ctuTsAddr=0, ctuRsAddr=0; ctuTsAddrgetNumTileColumnsMinus1() ); + setNumTileRowsMinus1( pps->getNumTileRowsMinus1() ); + + const Int numCols = pps->getNumTileColumnsMinus1() + 1; + const Int numRows = pps->getNumTileRowsMinus1() + 1; + const Int numTiles = numRows * numCols; + + // allocate memory for tile parameters + m_tileParameters.resize(numTiles); + + if( pps->getTileUniformSpacingFlag() ) + { + //set width and height for each (uniform) tile + for(Int row=0; row < numRows; row++) + { + for(Int col=0; col < numCols; col++) + { + const Int tileIdx = row * numCols + col; + m_tileParameters[tileIdx].setTileWidthInCtus( (col+1)*getFrameWidthInCtus( )/numCols - (col*getFrameWidthInCtus( ))/numCols ); + m_tileParameters[tileIdx].setTileHeightInCtus( (row+1)*getFrameHeightInCtus()/numRows - (row*getFrameHeightInCtus())/numRows ); + } + } + } + else + { + //set the width for each tile + for(Int row=0; row < numRows; row++) + { + Int cumulativeTileWidth = 0; + for(Int col=0; col < getNumTileColumnsMinus1(); col++) + { + m_tileParameters[row * numCols + col].setTileWidthInCtus( pps->getTileColumnWidth(col) ); + cumulativeTileWidth += pps->getTileColumnWidth(col); + } + m_tileParameters[row * numCols + getNumTileColumnsMinus1()].setTileWidthInCtus( getFrameWidthInCtus()-cumulativeTileWidth ); + } + + //set the height for each tile + for(Int col=0; col < numCols; col++) + { + Int cumulativeTileHeight = 0; + for(Int row=0; row < getNumTileRowsMinus1(); row++) + { + m_tileParameters[row * numCols + col].setTileHeightInCtus( pps->getTileRowHeight(row) ); + cumulativeTileHeight += pps->getTileRowHeight(row); + } + m_tileParameters[getNumTileRowsMinus1() * numCols + col].setTileHeightInCtus( getFrameHeightInCtus()-cumulativeTileHeight ); + } + } + +#if TILE_SIZE_CHECK + Int minWidth = 1; + Int minHeight = 1; + const Int profileIdc = pps->getSPS()->getPTL()->getGeneralPTL()->getProfileIdc(); + if ( profileIdc == Profile::MAIN || profileIdc == Profile::MAIN10) //TODO: add more profiles to the tile-size check... + { + if (pps->getTilesEnabledFlag()) + { + minHeight = 64 / g_uiMaxCUHeight; + minWidth = 256 / g_uiMaxCUWidth; + } + } + for(Int row=0; row < numRows; row++) + { + for(Int col=0; col < numCols; col++) + { + const Int tileIdx = row * numCols + col; + assert (m_tileParameters[tileIdx].getTileWidthInCtus() >= minWidth); + assert (m_tileParameters[tileIdx].getTileHeightInCtus() >= minHeight); + } + } +#endif + + //initialize each tile of the current picture + for( Int row=0; row < numRows; row++ ) + { + for( Int col=0; col < numCols; col++ ) + { + const Int tileIdx = row * numCols + col; + + //initialize the RightEdgePosInCU for each tile + Int rightEdgePosInCTU = 0; + for( Int i=0; i <= col; i++ ) + { + rightEdgePosInCTU += m_tileParameters[row * numCols + i].getTileWidthInCtus(); + } + m_tileParameters[tileIdx].setRightEdgePosInCtus(rightEdgePosInCTU-1); + + //initialize the BottomEdgePosInCU for each tile + Int bottomEdgePosInCTU = 0; + for( Int i=0; i <= row; i++ ) + { + bottomEdgePosInCTU += m_tileParameters[i * numCols + col].getTileHeightInCtus(); + } + m_tileParameters[tileIdx].setBottomEdgePosInCtus(bottomEdgePosInCTU-1); + + //initialize the FirstCUAddr for each tile + m_tileParameters[tileIdx].setFirstCtuRsAddr( (m_tileParameters[tileIdx].getBottomEdgePosInCtus() - m_tileParameters[tileIdx].getTileHeightInCtus() + 1) * getFrameWidthInCtus() + + m_tileParameters[tileIdx].getRightEdgePosInCtus() - m_tileParameters[tileIdx].getTileWidthInCtus() + 1); + } + } + + Int columnIdx = 0; + Int rowIdx = 0; + + //initialize the TileIdxMap + for( Int i=0; igetRightEdgePosInCtus() && currCtuRsAddr / m_frameWidthInCtus == getTComTile(uiTileIdx)->getBottomEdgePosInCtus() ) + //the current CTU is the last CTU of the tile + { + if(uiTileIdx+1 == getNumTiles()) + { + nextCtuRsAddr = m_numCtusInFrame; + } + else + { + nextCtuRsAddr = getTComTile(uiTileIdx+1)->getFirstCtuRsAddr(); + } + } + else //the current CTU is not the last CTU of the tile + { + if( currCtuRsAddr % m_frameWidthInCtus == getTComTile(uiTileIdx)->getRightEdgePosInCtus() ) //the current CTU is on the rightmost edge of the tile + { + nextCtuRsAddr = currCtuRsAddr + m_frameWidthInCtus - getTComTile(uiTileIdx)->getTileWidthInCtus() + 1; + } + else + { + nextCtuRsAddr = currCtuRsAddr + 1; + } + } + + return nextCtuRsAddr; +} + +Void TComPicSym::deriveLoopFilterBoundaryAvailibility(Int ctuRsAddr, + Bool& isLeftAvail, + Bool& isRightAvail, + Bool& isAboveAvail, + Bool& isBelowAvail, + Bool& isAboveLeftAvail, + Bool& isAboveRightAvail, + Bool& isBelowLeftAvail, + Bool& isBelowRightAvail + ) +{ + + isLeftAvail = (ctuRsAddr % m_frameWidthInCtus != 0); + isRightAvail = (ctuRsAddr % m_frameWidthInCtus != m_frameWidthInCtus-1); + isAboveAvail = (ctuRsAddr >= m_frameWidthInCtus ); + isBelowAvail = (ctuRsAddr < m_numCtusInFrame - m_frameWidthInCtus); + isAboveLeftAvail = (isAboveAvail && isLeftAvail); + isAboveRightAvail= (isAboveAvail && isRightAvail); + isBelowLeftAvail = (isBelowAvail && isLeftAvail); + isBelowRightAvail= (isBelowAvail && isRightAvail); + + Bool isLoopFiltAcrossTilePPS = getCtu(ctuRsAddr)->getSlice()->getPPS()->getLoopFilterAcrossTilesEnabledFlag(); + + { + TComDataCU* ctuCurr = getCtu(ctuRsAddr); + TComDataCU* ctuLeft = isLeftAvail ?getCtu(ctuRsAddr-1):NULL; + TComDataCU* ctuRight = isRightAvail?getCtu(ctuRsAddr+1):NULL; + TComDataCU* ctuAbove = isAboveAvail?getCtu(ctuRsAddr-m_frameWidthInCtus):NULL; + TComDataCU* ctuBelow = isBelowAvail?getCtu(ctuRsAddr+m_frameWidthInCtus):NULL; + TComDataCU* ctuAboveLeft = isAboveLeftAvail ? getCtu(ctuRsAddr-m_frameWidthInCtus-1):NULL; + TComDataCU* ctuAboveRight = isAboveRightAvail? getCtu(ctuRsAddr-m_frameWidthInCtus+1):NULL; + TComDataCU* ctuBelowLeft = isBelowLeftAvail ? getCtu(ctuRsAddr+m_frameWidthInCtus-1):NULL; + TComDataCU* ctuBelowRight = isBelowRightAvail? getCtu(ctuRsAddr+m_frameWidthInCtus+1):NULL; + + { + //left + if(ctuLeft != NULL) + { + isLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuLeft->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + //above + if(ctuAbove != NULL) + { + isAboveAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuAbove->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + //right + if(ctuRight != NULL) + { + isRightAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuRight->getSlice()->getSliceCurStartCtuTsAddr())?ctuRight->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + //below + if(ctuBelow != NULL) + { + isBelowAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuBelow->getSlice()->getSliceCurStartCtuTsAddr())?ctuBelow->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + //above-left + if(ctuAboveLeft != NULL) + { + isAboveLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuAboveLeft->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + //below-right + if(ctuBelowRight != NULL) + { + isBelowRightAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuBelowRight->getSlice()->getSliceCurStartCtuTsAddr())?ctuBelowRight->getSlice()->getLFCrossSliceBoundaryFlag():true; + } + + //above-right + if(ctuAboveRight != NULL) + { + Int curSliceStartTsAddr = ctuCurr->getSlice()->getSliceCurStartCtuTsAddr(); + Int aboveRightSliceStartTsAddr = ctuAboveRight->getSlice()->getSliceCurStartCtuTsAddr(); + + isAboveRightAvail = (curSliceStartTsAddr == aboveRightSliceStartTsAddr)?(true): + ( + (curSliceStartTsAddr > aboveRightSliceStartTsAddr)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag()) + :(ctuAboveRight->getSlice()->getLFCrossSliceBoundaryFlag()) + ); + } + //below-left + if(ctuBelowLeft != NULL) + { + Int curSliceStartTsAddr = ctuCurr->getSlice()->getSliceCurStartCtuTsAddr(); + Int belowLeftSliceStartTsAddr = ctuBelowLeft->getSlice()->getSliceCurStartCtuTsAddr(); + + isBelowLeftAvail = (curSliceStartTsAddr == belowLeftSliceStartTsAddr)?(true): + ( + (curSliceStartTsAddr > belowLeftSliceStartTsAddr)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag()) + :(ctuBelowLeft->getSlice()->getLFCrossSliceBoundaryFlag()) + ); + } + } + + if(!isLoopFiltAcrossTilePPS) + { + isLeftAvail = (!isLeftAvail ) ?false:(getTileIdxMap( ctuLeft->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isAboveAvail = (!isAboveAvail ) ?false:(getTileIdxMap( ctuAbove->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isRightAvail = (!isRightAvail ) ?false:(getTileIdxMap( ctuRight->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isBelowAvail = (!isBelowAvail ) ?false:(getTileIdxMap( ctuBelow->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isAboveLeftAvail = (!isAboveLeftAvail ) ?false:(getTileIdxMap( ctuAboveLeft->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isAboveRightAvail= (!isAboveRightAvail) ?false:(getTileIdxMap( ctuAboveRight->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isBelowLeftAvail = (!isBelowLeftAvail ) ?false:(getTileIdxMap( ctuBelowLeft->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + isBelowRightAvail= (!isBelowRightAvail) ?false:(getTileIdxMap( ctuBelowRight->getCtuRsAddr() ) == getTileIdxMap( ctuRsAddr )); + } + } + +} + + +TComTile::TComTile() +: m_tileWidthInCtus (0) +, m_tileHeightInCtus (0) +, m_rightEdgePosInCtus (0) +, m_bottomEdgePosInCtus (0) +, m_firstCtuRsAddr (0) +{ +} + +TComTile::~TComTile() +{ +} +//! \} diff --git a/jctvc/TLibCommon/TComPicSym.h b/jctvc/TLibCommon/TComPicSym.h new file mode 100644 index 0000000..a9ee04e --- /dev/null +++ b/jctvc/TLibCommon/TComPicSym.h @@ -0,0 +1,162 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPicSym.h + \brief picture symbol class (header) +*/ + +#ifndef __TCOMPICSYM__ +#define __TCOMPICSYM__ + + +// Include files +#include "CommonDef.h" +#include "TComSlice.h" +#include "TComDataCU.h" +class TComSampleAdaptiveOffset; +class TComPPS; + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +class TComTile +{ +private: + UInt m_tileWidthInCtus; + UInt m_tileHeightInCtus; + UInt m_rightEdgePosInCtus; + UInt m_bottomEdgePosInCtus; + UInt m_firstCtuRsAddr; + +public: + TComTile(); + virtual ~TComTile(); + + Void setTileWidthInCtus ( UInt i ) { m_tileWidthInCtus = i; } + UInt getTileWidthInCtus () const { return m_tileWidthInCtus; } + Void setTileHeightInCtus ( UInt i ) { m_tileHeightInCtus = i; } + UInt getTileHeightInCtus () const { return m_tileHeightInCtus; } + Void setRightEdgePosInCtus ( UInt i ) { m_rightEdgePosInCtus = i; } + UInt getRightEdgePosInCtus () const { return m_rightEdgePosInCtus; } + Void setBottomEdgePosInCtus ( UInt i ) { m_bottomEdgePosInCtus = i; } + UInt getBottomEdgePosInCtus () const { return m_bottomEdgePosInCtus; } + Void setFirstCtuRsAddr ( UInt i ) { m_firstCtuRsAddr = i; } + UInt getFirstCtuRsAddr () const { return m_firstCtuRsAddr; } +}; + +/// picture symbol class +class TComPicSym +{ +private: + UInt m_frameWidthInCtus; + UInt m_frameHeightInCtus; + + UInt m_uiMaxCUWidth; + UInt m_uiMaxCUHeight; + UInt m_uiMinCUWidth; + UInt m_uiMinCUHeight; + + UChar m_uhTotalDepth; ///< max. depth + UInt m_numPartitionsInCtu; + UInt m_numPartInCtuWidth; + UInt m_numPartInCtuHeight; + UInt m_numCtusInFrame; + + TComSlice** m_apcTComSlice; + UInt m_uiNumAllocatedSlice; + TComDataCU** m_pictureCtuArray; ///< array of CU data. + + Int m_numTileColumnsMinus1; + Int m_numTileRowsMinus1; + std::vector m_tileParameters; + UInt* m_ctuTsToRsAddrMap; ///< for a given TS (Tile-Scan; coding order) address, returns the RS (Raster-Scan) address. cf CtbAddrTsToRs in specification. + UInt* m_puiTileIdxMap; ///< the map of the tile index relative to CTU raster scan address + UInt* m_ctuRsToTsAddrMap; ///< for a given RS (Raster-Scan) address, returns the TS (Tile-Scan; coding order) address. cf CtbAddrRsToTs in specification. + + SAOBlkParam *m_saoBlkParams; + +public: + Void create ( ChromaFormat chromaFormatIDC, Int iPicWidth, Int iPicHeight, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth ); + Void destroy (); + + TComPicSym (); + TComSlice* getSlice(UInt i) { return m_apcTComSlice[i]; } + const TComSlice* getSlice(UInt i) const { return m_apcTComSlice[i]; } + UInt getFrameWidthInCtus() const { return m_frameWidthInCtus; } + UInt getFrameHeightInCtus() const { return m_frameHeightInCtus; } + UInt getMinCUWidth() const { return m_uiMinCUWidth; } + UInt getMinCUHeight() const { return m_uiMinCUHeight; } + UInt getNumberOfCtusInFrame() const { return m_numCtusInFrame; } + TComDataCU* getCtu( UInt ctuRsAddr ) { return m_pictureCtuArray[ctuRsAddr]; } + const TComDataCU* getCtu( UInt ctuRsAddr ) const { return m_pictureCtuArray[ctuRsAddr]; } + + Void setSlice(TComSlice* p, UInt i) { m_apcTComSlice[i] = p; } + UInt getNumAllocatedSlice() const { return m_uiNumAllocatedSlice; } + Void allocateNewSlice(); + Void clearSliceBuffer(); + UInt getNumPartitionsInCtu() const { return m_numPartitionsInCtu; } + UInt getNumPartInCtuWidth() const { return m_numPartInCtuWidth; } + UInt getNumPartInCtuHeight() const { return m_numPartInCtuHeight; } + Void setNumTileColumnsMinus1( Int i ) { m_numTileColumnsMinus1 = i; } + Int getNumTileColumnsMinus1() const { return m_numTileColumnsMinus1; } + Void setNumTileRowsMinus1( Int i ) { m_numTileRowsMinus1 = i; } + Int getNumTileRowsMinus1() const { return m_numTileRowsMinus1; } + Int getNumTiles() const { return (m_numTileRowsMinus1+1)*(m_numTileColumnsMinus1+1); } + TComTile* getTComTile ( UInt tileIdx ) { return &(m_tileParameters[tileIdx]); } + const TComTile* getTComTile ( UInt tileIdx ) const { return &(m_tileParameters[tileIdx]); } + Void setCtuTsToRsAddrMap( Int ctuTsAddr, Int ctuRsAddr ) { *(m_ctuTsToRsAddrMap + ctuTsAddr) = ctuRsAddr; } + UInt getCtuTsToRsAddrMap( Int ctuTsAddr ) const { return *(m_ctuTsToRsAddrMap + (ctuTsAddr>=m_numCtusInFrame ? m_numCtusInFrame : ctuTsAddr)); } + UInt getTileIdxMap( Int ctuRsAddr ) const { return *(m_puiTileIdxMap + ctuRsAddr); } + Void setCtuRsToTsAddrMap( Int ctuRsAddr, Int ctuTsOrder ) { *(m_ctuRsToTsAddrMap + ctuRsAddr) = ctuTsOrder; } + UInt getCtuRsToTsAddrMap( Int ctuRsAddr ) const { return *(m_ctuRsToTsAddrMap + (ctuRsAddr>=m_numCtusInFrame ? m_numCtusInFrame : ctuRsAddr)); } + Void initTiles(TComPPS *pps); + + Void initCtuTsRsAddrMaps(); + SAOBlkParam* getSAOBlkParam() { return m_saoBlkParams;} + const SAOBlkParam* getSAOBlkParam() const { return m_saoBlkParams;} + Void deriveLoopFilterBoundaryAvailibility(Int ctuRsAddr, + Bool& isLeftAvail, Bool& isRightAvail, Bool& isAboveAvail, Bool& isBelowAvail, + Bool& isAboveLeftAvail, Bool& isAboveRightAvail, Bool& isBelowLeftAvail, Bool& isBelowRightAvail); +protected: + UInt xCalculateNextCtuRSAddr( UInt uiCurrCtuRSAddr ); + +};// END CLASS DEFINITION TComPicSym + +//! \} + +#endif // __TCOMPICSYM__ + diff --git a/jctvc/TLibCommon/TComPicYuv.cpp b/jctvc/TLibCommon/TComPicYuv.cpp new file mode 100644 index 0000000..b95ece6 --- /dev/null +++ b/jctvc/TLibCommon/TComPicYuv.cpp @@ -0,0 +1,257 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPicYuv.cpp + \brief picture YUV buffer class +*/ + +#include +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "TComPicYuv.h" +#include "TLibVideoIO/TVideoIOYuv.h" + +//! \ingroup TLibCommon +//! \{ + +TComPicYuv::TComPicYuv() +{ + for(UInt i=0; i> getComponentScaleY(ch)) * getStride(ch) + (m_iMarginX >> getComponentScaleX(ch)); + } + for(;chan>getComponentScaleY(ch); + const Int ctuWidth=uiMaxCUWidth>>getComponentScaleX(ch); + const Int stride = getStride(ch); + + m_ctuOffsetInBuffer[chan] = new Int[numCuInWidth * numCuInHeight]; + + for (Int cuRow = 0; cuRow < numCuInHeight; cuRow++) + for (Int cuCol = 0; cuCol < numCuInWidth; cuCol++) + m_ctuOffsetInBuffer[chan][cuRow * numCuInWidth + cuCol] = stride * cuRow * ctuHeight + cuCol * ctuWidth; + + m_subCuOffsetInBuffer[chan] = new Int[(size_t)1 << (2 * uiMaxCUDepth)]; + + const Int numSubBlockPartitions=(1<> uiMaxCUDepth); + const Int minSubBlockWidth =(ctuWidth >> uiMaxCUDepth); + + for (Int buRow = 0; buRow < numSubBlockPartitions; buRow++) + for (Int buCol = 0; buCol < numSubBlockPartitions; buCol++) + m_subCuOffsetInBuffer[chan][(buRow << uiMaxCUDepth) + buCol] = stride * buRow * minSubBlockHeight + buCol * minSubBlockWidth; + } + return; +} + + + +Void TComPicYuv::destroy() +{ + for(Int chan=0; changetWidth(COMPONENT_Y) ); + assert( m_iPicHeight == pcPicYuvDst->getHeight(COMPONENT_Y) ); + assert( m_chromaFormatIDC == pcPicYuvDst->getChromaFormat() ); + + for(Int chan=0; changetBuf(ch), m_apiPicBuf[ch], sizeof (Pel) * getStride(ch) * getTotalHeight(ch)); + } + return; +} + + +Void TComPicYuv::extendPicBorder () +{ + if ( m_bIsBorderExtended ) return; + + for(Int chan=0; chan0)?(1<<(shift-1)):0; + const Pel *pi = getAddr(ch); + const Int stride = getStride(ch); + const Int height = getHeight(ch); + const Int width = getWidth(ch); + + for (Int y = 0; y < height; y++ ) + { + for (Int x = 0; x < width; x++ ) + { + UChar uc = (UChar)Clip3(0, 255, (pi[x]+offset)>>shift); + fwrite( &uc, sizeof(UChar), 1, pFile ); + } + pi += stride; + } + } + + fclose(pFile); +} + +//! \} diff --git a/jctvc/TLibCommon/TComPicYuv.h b/jctvc/TLibCommon/TComPicYuv.h new file mode 100644 index 0000000..7f76b4b --- /dev/null +++ b/jctvc/TLibCommon/TComPicYuv.h @@ -0,0 +1,166 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPicYuv.h + \brief picture YUV buffer class (header) +*/ + +#ifndef __TCOMPICYUV__ +#define __TCOMPICYUV__ + +#include +#include "CommonDef.h" +#include "TComRom.h" +#include "TComChromaFormat.h" +#include "SEI.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// picture YUV buffer class +class TComPicYuv +{ +private: + + // ------------------------------------------------------------------------------------------------ + // YUV buffer + // ------------------------------------------------------------------------------------------------ + + Pel* m_apiPicBuf[MAX_NUM_COMPONENT]; ///< Buffer (including margin) + + Pel* m_piPicOrg[MAX_NUM_COMPONENT]; ///< m_apiPicBufY + m_iMarginLuma*getStride() + m_iMarginLuma + + // ------------------------------------------------------------------------------------------------ + // Parameter for general YUV buffer usage + // ------------------------------------------------------------------------------------------------ + + Int m_iPicWidth; ///< Width of picture in pixels + Int m_iPicHeight; ///< Height of picture in pixels + ChromaFormat m_chromaFormatIDC; ///< Chroma Format + + Int* m_ctuOffsetInBuffer[MAX_NUM_CHANNEL_TYPE]; ///< Gives an offset in the buffer for a given CTU (and channel) + Int* m_subCuOffsetInBuffer[MAX_NUM_CHANNEL_TYPE];///< Gives an offset in the buffer for a given sub-CU (and channel), relative to start of CTU + + Int m_iMarginX; ///< margin of Luma channel (chroma's may be smaller, depending on ratio) + Int m_iMarginY; ///< margin of Luma channel (chroma's may be smaller, depending on ratio) + + Bool m_bIsBorderExtended; + +public: + TComPicYuv (); + virtual ~TComPicYuv (); + + // ------------------------------------------------------------------------------------------------ + // Memory management + // ------------------------------------------------------------------------------------------------ + + Void create (const Int iPicWidth, + const Int iPicHeight, + const ChromaFormat chromaFormatIDC, + const UInt uiMaxCUWidth, + const UInt uiMaxCUHeight, + const UInt uiMaxCUDepth ); + + Void destroy (); + + // The following have been removed - Use CHROMA_400 in the above function call. + //Void createLuma ( Int iPicWidth, Int iPicHeight, UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uhMaxCUDepth ); + //Void destroyLuma (); + + // ------------------------------------------------------------------------------------------------ + // Get information of picture + // ------------------------------------------------------------------------------------------------ + + Int getWidth (const ComponentID id) const { return m_iPicWidth >> getComponentScaleX(id); } + Int getHeight (const ComponentID id) const { return m_iPicHeight >> getComponentScaleY(id); } + ChromaFormat getChromaFormat () const { return m_chromaFormatIDC; } + UInt getNumberValidComponents() const { return ::getNumberValidComponents(m_chromaFormatIDC); } + + Int getStride (const ComponentID id) const { return ((m_iPicWidth ) + (m_iMarginX <<1)) >> getComponentScaleX(id); } + Int getTotalHeight (const ComponentID id) const { return ((m_iPicHeight ) + (m_iMarginY <<1)) >> getComponentScaleY(id); } + + Int getMarginX (const ComponentID id) const { return m_iMarginX >> getComponentScaleX(id); } + Int getMarginY (const ComponentID id) const { return m_iMarginY >> getComponentScaleY(id); } + + // ------------------------------------------------------------------------------------------------ + // Access function for picture buffer + // ------------------------------------------------------------------------------------------------ + + // Access starting position of picture buffer with margin + Pel* getBuf (const ComponentID ch) { return m_apiPicBuf[ch]; } + + // Access starting position of original picture + Pel* getAddr (const ComponentID ch) { return m_piPicOrg[ch]; } + const Pel* getAddr (const ComponentID ch) const { return m_piPicOrg[ch]; } + + // Access starting position of original picture for specific coding unit (CU) or partition unit (PU) + Pel* getAddr (const ComponentID ch, const Int ctuRSAddr ) { return m_piPicOrg[ch] + m_ctuOffsetInBuffer[ch==0?0:1][ ctuRSAddr ]; } + const Pel* getAddr (const ComponentID ch, const Int ctuRSAddr ) const { return m_piPicOrg[ch] + m_ctuOffsetInBuffer[ch==0?0:1][ ctuRSAddr ]; } + Pel* getAddr (const ComponentID ch, const Int ctuRSAddr, const Int uiAbsZorderIdx ) + { return m_piPicOrg[ch] + m_ctuOffsetInBuffer[ch==0?0:1][ctuRSAddr] + m_subCuOffsetInBuffer[ch==0?0:1][g_auiZscanToRaster[uiAbsZorderIdx]]; } + const Pel* getAddr (const ComponentID ch, const Int ctuRSAddr, const Int uiAbsZorderIdx ) const + { return m_piPicOrg[ch] + m_ctuOffsetInBuffer[ch==0?0:1][ctuRSAddr] + m_subCuOffsetInBuffer[ch==0?0:1][g_auiZscanToRaster[uiAbsZorderIdx]]; } + + UInt getComponentScaleX(const ComponentID id) const { return ::getComponentScaleX(id, m_chromaFormatIDC); } + UInt getComponentScaleY(const ComponentID id) const { return ::getComponentScaleY(id, m_chromaFormatIDC); } + + // ------------------------------------------------------------------------------------------------ + // Miscellaneous + // ------------------------------------------------------------------------------------------------ + + // Copy function to picture + Void copyToPic ( TComPicYuv* pcPicYuvDst ) const ; + + // Extend function of picture buffer + Void extendPicBorder (); + + // Dump picture + Void dump (const Char* pFileName, Bool bAdd = false) const ; + + // Set border extension flag + Void setBorderExtension(Bool b) { m_bIsBorderExtended = b; } +};// END CLASS DEFINITION TComPicYuv + + +// These functions now return the length of the digest strings. +UInt calcChecksum(const TComPicYuv& pic, TComDigest &digest); +UInt calcCRC (const TComPicYuv& pic, TComDigest &digest); +UInt calcMD5 (const TComPicYuv& pic, TComDigest &digest); +std::string digestToString(const TComDigest &digest, Int numChar); +//! \} + +#endif // __TCOMPICYUV__ diff --git a/jctvc/TLibCommon/TComPicYuvMD5.cpp b/jctvc/TLibCommon/TComPicYuvMD5.cpp new file mode 100644 index 0000000..580e273 --- /dev/null +++ b/jctvc/TLibCommon/TComPicYuvMD5.cpp @@ -0,0 +1,222 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TComPicYuv.h" +#include "libmd5/MD5.h" + +//! \ingroup TLibCommon +//! \{ + +/** + * Update md5 using n samples from plane, each sample is adjusted to + * OUTBIT_BITDEPTH_DIV8. + */ +template +static Void md5_block(MD5& md5, const Pel* plane, UInt n) +{ + /* create a 64 byte buffer for packing Pel's into */ + UChar buf[64/OUTPUT_BITDEPTH_DIV8][OUTPUT_BITDEPTH_DIV8]; + for (UInt i = 0; i < n; i++) + { + Pel pel = plane[i]; + /* perform bitdepth and endian conversion */ + for (UInt d = 0; d < OUTPUT_BITDEPTH_DIV8; d++) + { + buf[i][d] = pel >> (d*8); + } + } + md5.update((UChar*)buf, n * OUTPUT_BITDEPTH_DIV8); +} + +/** + * Update md5 with all samples in plane in raster order, each sample + * is adjusted to OUTBIT_BITDEPTH_DIV8. + */ +template +static Void md5_plane(MD5& md5, const Pel* plane, UInt width, UInt height, UInt stride) +{ + /* N is the number of samples to process per md5 update. + * All N samples must fit in buf */ + UInt N = 32; + UInt width_modN = width % N; + UInt width_less_modN = width - width_modN; + + for (UInt y = 0; y < height; y++) + { + /* convert pels into unsigned chars in little endian byte order. + * NB, for 8bit data, data is truncated to 8bits. */ + for (UInt x = 0; x < width_less_modN; x += N) + md5_block(md5, &plane[y*stride + x], N); + + /* mop up any of the remaining line */ + md5_block(md5, &plane[y*stride + width_less_modN], width_modN); + } +} + + +UInt compCRC(Int bitdepth, const Pel* plane, UInt width, UInt height, UInt stride, TComDigest &digest) +{ + UInt crcMsb; + UInt bitVal; + UInt crcVal = 0xffff; + UInt bitIdx; + for (UInt y = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++) + { + // take CRC of first pictureData byte + for(bitIdx=0; bitIdx<8; bitIdx++) + { + crcMsb = (crcVal >> 15) & 1; + bitVal = (plane[y*stride+x] >> (7 - bitIdx)) & 1; + crcVal = (((crcVal << 1) + bitVal) & 0xffff) ^ (crcMsb * 0x1021); + } + // take CRC of second pictureData byte if bit depth is greater than 8-bits + if(bitdepth > 8) + { + for(bitIdx=0; bitIdx<8; bitIdx++) + { + crcMsb = (crcVal >> 15) & 1; + bitVal = (plane[y*stride+x] >> (15 - bitIdx)) & 1; + crcVal = (((crcVal << 1) + bitVal) & 0xffff) ^ (crcMsb * 0x1021); + } + } + } + } + for(bitIdx=0; bitIdx<16; bitIdx++) + { + crcMsb = (crcVal >> 15) & 1; + crcVal = ((crcVal << 1) & 0xffff) ^ (crcMsb * 0x1021); + } + + digest.hash.push_back((crcVal>>8) & 0xff); + digest.hash.push_back( crcVal & 0xff); + return 2; +} + +UInt calcCRC(const TComPicYuv& pic, TComDigest &digest) +{ + UInt digestLen=0; + digest.hash.clear(); + for(Int chan=0; chan> 8) ^ (y >> 8); + checksum = (checksum + ((plane[y*stride+x] & 0xff) ^ xor_mask)) & 0xffffffff; + + if(bitdepth > 8) + { + checksum = (checksum + ((plane[y*stride+x]>>8) ^ xor_mask)) & 0xffffffff; + } + } + } + + digest.hash.push_back((checksum>>24) & 0xff); + digest.hash.push_back((checksum>>16) & 0xff); + digest.hash.push_back((checksum>>8) & 0xff); + digest.hash.push_back( checksum & 0xff); + return 4; +} + +UInt calcChecksum(const TComPicYuv& pic, TComDigest &digest) +{ + UInt digestLen=0; + digest.hash.clear(); + for(Int chan=0; chan : (MD5PlaneFunc)md5_plane<2>; + UChar tmp_digest[MD5_DIGEST_STRING_LENGTH]; + md5_plane_func(md5[compID], pic.getAddr(compID), pic.getWidth(compID), pic.getHeight(compID), pic.getStride(compID)); + md5[compID].finalize(tmp_digest); + for(UInt i=0; i> 4]; + result += hex[digest.hash[pos] & 0xf]; + } + + return result; +} + +//! \} diff --git a/jctvc/TLibCommon/TComPrediction.cpp b/jctvc/TLibCommon/TComPrediction.cpp new file mode 100644 index 0000000..6e268f0 --- /dev/null +++ b/jctvc/TLibCommon/TComPrediction.cpp @@ -0,0 +1,841 @@ +/* The copyright in this software is beinOMg made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPrediction.cpp + \brief prediction class +*/ + +#include +#include "TComPrediction.h" +#include "TComTU.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Tables +// ==================================================================================================================== + +const UChar TComPrediction::m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS] = +{ + { // Luma + 10, //4x4 + 7, //8x8 + 1, //16x16 + 0, //32x32 + 10, //64x64 + }, + { // Chroma + 10, //4xn + 7, //8xn + 1, //16xn + 0, //32xn + 10, //64xn + } + +}; + +// ==================================================================================================================== +// Constructor / destructor / initialize +// ==================================================================================================================== + +TComPrediction::TComPrediction() +: m_pLumaRecBuffer(0) +, m_iLumaRecStride(0) +{ + for(UInt ch=0; ch>1) + 1) + { + m_iLumaRecStride = (MAX_CU_SIZE>>1) + 1; + if (!m_pLumaRecBuffer) + { + m_pLumaRecBuffer = new Pel[ m_iLumaRecStride * m_iLumaRecStride ]; + } + } +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +// Function for calculating DC value of the reference samples used in Intra prediction +//NOTE: Bit-Limit - 25-bit source +Pel TComPrediction::predIntraGetPredValDC( const Pel* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight, ChannelType channelType, ChromaFormat format, Bool bAbove, Bool bLeft ) +{ + assert(iWidth > 0 && iHeight > 0); + Int iInd, iSum = 0; + Pel pDcVal; + + if (bAbove) + { + for (iInd = 0;iInd < iWidth;iInd++) + { + iSum += pSrc[iInd-iSrcStride]; + } + } + if (bLeft) + { + for (iInd = 0;iInd < iHeight;iInd++) + { + iSum += pSrc[iInd*iSrcStride-1]; + } + } + + if (bAbove && bLeft) + { + pDcVal = (iSum + iWidth) / (iWidth + iHeight); + } + else if (bAbove) + { + pDcVal = (iSum + iWidth/2) / iWidth; + } + else if (bLeft) + { + pDcVal = (iSum + iHeight/2) / iHeight; + } + else + { + pDcVal = pSrc[-1]; // Default DC value already calculated and placed in the prediction array if no neighbors are available + } + + return pDcVal; +} + +// Function for deriving the angular Intra predictions + +/** Function for deriving the simplified angular intra predictions. + * \param pSrc pointer to reconstructed sample array + * \param srcStride the stride of the reconstructed sample array + * \param rpDst reference to pointer for the prediction sample array + * \param dstStride the stride of the prediction sample array + * \param width the width of the block + * \param height the height of the block + * \param dirMode the intra prediction mode index + * \param blkAboveAvailable boolean indication if the block above is available + * \param blkLeftAvailable boolean indication if the block to the left is available + * + * This function derives the prediction samples for the angular mode based on the prediction direction indicated by + * the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and + * the reference row above the block in the case of vertical prediction or displacement of the rightmost column + * of the block and reference column left from the block in the case of the horizontal prediction. The displacement + * is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples, + * the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken + * from the extended main reference. + */ +//NOTE: Bit-Limit - 25-bit source +Void TComPrediction::xPredIntraAng( Int bitDepth, + const Pel* pSrc, Int srcStride, + Pel* pTrueDst, Int dstStrideTrue, + UInt uiWidth, UInt uiHeight, ChannelType channelType, ChromaFormat format, + UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable + , const Bool bEnableEdgeFilters + ) +{ + Int width=Int(uiWidth); + Int height=Int(uiHeight); + + // Map the mode index to main prediction direction and angle + assert( dirMode != PLANAR_IDX ); //no planar + const Bool modeDC = dirMode==DC_IDX; + + // Do the DC prediction + if (modeDC) + { + const Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, channelType, format, blkAboveAvailable, blkLeftAvailable); + + for (Int y=height;y>0;y--, pTrueDst+=dstStrideTrue) + { + for (Int x=0; x= 18); + const Int intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX : -((Int)dirMode - HOR_IDX); + const Int absAngMode = abs(intraPredAngleMode); + const Int signAng = intraPredAngleMode < 0 ? -1 : 1; + const Bool edgeFilter = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <= MAXIMUM_INTRA_FILTERED_HEIGHT); + + // Set bitshifts and scale the angle parameter to block size + static const Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32}; + static const Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle + Int invAngle = invAngTable[absAngMode]; + Int absAng = angTable[absAngMode]; + Int intraPredAngle = signAng * absAng; + + Pel* refMain; + Pel* refSide; + + Pel refAbove[2*MAX_CU_SIZE+1]; + Pel refLeft[2*MAX_CU_SIZE+1]; + + // Initialise the Main and Left reference array. + if (intraPredAngle < 0) + { + const Int refMainOffsetPreScale = (bIsModeVer ? height : width ) - 1; + const Int refMainOffset = height - 1; + for (Int x=0;x(refMainOffsetPreScale+1)*intraPredAngle>>5; k--) + { + invAngleSum += invAngle; + refMain[k] = refSide[invAngleSum>>8]; + } + } + else + { + for (Int x=0;x<2*width+1;x++) + { + refAbove[x] = pSrc[x-srcStride-1]; + } + for (Int y=0;y<2*height+1;y++) + { + refLeft[y] = pSrc[(y-1)*srcStride-1]; + } + refMain = bIsModeVer ? refAbove : refLeft ; + refSide = bIsModeVer ? refLeft : refAbove; + } + + // swap width/height if we are doing a horizontal mode: + Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE]; + const Int dstStride = bIsModeVer ? dstStrideTrue : MAX_CU_SIZE; + Pel *pDst = bIsModeVer ? pTrueDst : tempArray; + if (!bIsModeVer) + { + std::swap(width, height); + } + + if (intraPredAngle == 0) // pure vertical or pure horizontal + { + for (Int y=0;y> 1) ); + } + } + } + else + { + Pel *pDsty=pDst; + + for (Int y=0, deltaPos=intraPredAngle; y> 5; + const Int deltaFract = deltaPos & (32 - 1); + + if (deltaFract) + { + // Do linear filtering + const Pel *pRM=refMain+deltaInt+1; + Int lastRefMainPel=*pRM++; + for (Int x=0;x> 5 ); + lastRefMainPel=thisRefMainPel; + } + } + else + { + // Just copy the integer samples + for (Int x=0;x= 0 ); // 4x 4 + assert( g_aucConvertToBit[ iWidth ] <= 5 ); // 128x128 + //assert( iWidth == iHeight ); + + Pel *pDst = piPred; + + // get starting pixel in block + const Int sw = (2 * iWidth + 1); + + if ( bUseLosslessDPCM ) + { + const Pel *ptrSrc = getPredictorPtr( compID, false ); + // Sample Adaptive intra-Prediction (SAP) + if (uiDirMode==HOR_IDX) + { + // left column filled with reference samples + // remaining columns filled with piOrg data (if available). + for(Int y=0; yisRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx)); + +#if O0043_BEST_EFFORT_DECODING + xPredIntraAng( g_bitDepthInStream[channelType], ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType, format, uiDirMode, bAbove, bLeft, enableEdgeFilters ); +#else + xPredIntraAng( g_bitDepth[channelType], ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType, format, uiDirMode, bAbove, bLeft, enableEdgeFilters ); +#endif + + if(( uiDirMode == DC_IDX ) && bAbove && bLeft ) + { + xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType ); + } + } + } + +} + +/** Function for checking identical motion. + * \param TComDataCU* pcCU + * \param UInt PartAddr + */ +Bool TComPrediction::xCheckIdenticalMotion ( TComDataCU* pcCU, UInt PartAddr ) +{ + if( pcCU->getSlice()->isInterB() && !pcCU->getSlice()->getPPS()->getWPBiPred() ) + { + if( pcCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx(PartAddr) >= 0 && pcCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx(PartAddr) >= 0) + { + Int RefPOCL0 = pcCU->getSlice()->getRefPic(REF_PIC_LIST_0, pcCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx(PartAddr))->getPOC(); + Int RefPOCL1 = pcCU->getSlice()->getRefPic(REF_PIC_LIST_1, pcCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx(PartAddr))->getPOC(); + if(RefPOCL0 == RefPOCL1 && pcCU->getCUMvField(REF_PIC_LIST_0)->getMv(PartAddr) == pcCU->getCUMvField(REF_PIC_LIST_1)->getMv(PartAddr)) + { + return true; + } + } + } + return false; +} + +Void TComPrediction::motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList, Int iPartIdx ) +{ + Int iWidth; + Int iHeight; + UInt uiPartAddr; + + if ( iPartIdx >= 0 ) + { + pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); + if ( eRefPicList != REF_PIC_LIST_X ) + { + if( pcCU->getSlice()->getPPS()->getUseWP()) + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true ); + } + else + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); + } + if ( pcCU->getSlice()->getPPS()->getUseWP() ) + { + xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); + } + } + else + { + if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ) + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); + } + else + { + xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred ); + } + } + return; + } + + for ( iPartIdx = 0; iPartIdx < pcCU->getNumPartitions(); iPartIdx++ ) + { + pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); + + if ( eRefPicList != REF_PIC_LIST_X ) + { + if( pcCU->getSlice()->getPPS()->getUseWP()) + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true ); + } + else + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); + } + if ( pcCU->getSlice()->getPPS()->getUseWP() ) + { + xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); + } + } + else + { + if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ) + { + xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); + } + else + { + xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred ); + } + } + } + return; +} + +Void TComPrediction::xPredInterUni ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, RefPicList eRefPicList, TComYuv* pcYuvPred, Bool bi ) +{ + Int iRefIdx = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr ); assert (iRefIdx >= 0); + TComMv cMv = pcCU->getCUMvField( eRefPicList )->getMv( uiPartAddr ); + pcCU->clipMv(cMv); + + for (UInt ch=COMPONENT_Y; chgetNumberValidComponents(); ch++) + xPredInterBlk (ComponentID(ch), pcCU, pcCU->getSlice()->getRefPic( eRefPicList, iRefIdx )->getPicYuvRec(), uiPartAddr, &cMv, iWidth, iHeight, pcYuvPred, bi ); +} + +Void TComPrediction::xPredInterBi ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, TComYuv* pcYuvPred ) +{ + TComYuv* pcMbYuv; + Int iRefIdx[NUM_REF_PIC_LIST_01] = {-1, -1}; + + for ( UInt refList = 0; refList < NUM_REF_PIC_LIST_01; refList++ ) + { + RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0); + iRefIdx[refList] = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr ); + + if ( iRefIdx[refList] < 0 ) + { + continue; + } + + assert( iRefIdx[refList] < pcCU->getSlice()->getNumRefIdx(eRefPicList) ); + + pcMbYuv = &m_acYuvPred[refList]; + if( pcCU->getCUMvField( REF_PIC_LIST_0 )->getRefIdx( uiPartAddr ) >= 0 && pcCU->getCUMvField( REF_PIC_LIST_1 )->getRefIdx( uiPartAddr ) >= 0 ) + { + xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true ); + } + else + { + if ( ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType() == P_SLICE ) || + ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE ) ) + { + xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true ); + } + else + { + xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv ); + } + } + } + + if ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE ) + { + xWeightedPredictionBi( pcCU, &m_acYuvPred[REF_PIC_LIST_0], &m_acYuvPred[REF_PIC_LIST_1], iRefIdx[REF_PIC_LIST_0], iRefIdx[REF_PIC_LIST_1], uiPartAddr, iWidth, iHeight, pcYuvPred ); + } + else if ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType() == P_SLICE ) + { + xWeightedPredictionUni( pcCU, &m_acYuvPred[REF_PIC_LIST_0], uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); + } + else + { + xWeightedAverage( &m_acYuvPred[REF_PIC_LIST_0], &m_acYuvPred[REF_PIC_LIST_1], iRefIdx[REF_PIC_LIST_0], iRefIdx[REF_PIC_LIST_1], uiPartAddr, iWidth, iHeight, pcYuvPred ); + } +} + +/** + * \brief Generate motion-compensated block + * + * \param cu Pointer to current CU + * \param refPic Pointer to reference picture + * \param partAddr Address of block within CU + * \param mv Motion vector + * \param width Width of block + * \param height Height of block + * \param dstPic Pointer to destination picture + * \param bi Flag indicating whether bipred is used + */ + + +Void TComPrediction::xPredInterBlk(const ComponentID compID, TComDataCU *cu, TComPicYuv *refPic, UInt partAddr, TComMv *mv, Int width, Int height, TComYuv *dstPic, Bool bi ) +{ + Int refStride = refPic->getStride(compID); + Int dstStride = dstPic->getStride(compID); + Int shiftHor=(2+refPic->getComponentScaleX(compID)); + Int shiftVer=(2+refPic->getComponentScaleY(compID)); + + Int refOffset = (mv->getHor() >> shiftHor) + (mv->getVer() >> shiftVer) * refStride; + + Pel* ref = refPic->getAddr(compID, cu->getCtuRsAddr(), cu->getZorderIdxInCtu() + partAddr ) + refOffset; + + Pel* dst = dstPic->getAddr( compID, partAddr ); + + Int xFrac = mv->getHor() & ((1<getVer() & ((1<> refPic->getComponentScaleX(compID); + UInt cxHeight = height >> refPic->getComponentScaleY(compID); + + const ChromaFormat chFmt = cu->getPic()->getChromaFormat(); + + if ( yFrac == 0 ) + { + m_if.filterHor(compID, ref, refStride, dst, dstStride, cxWidth, cxHeight, xFrac, !bi, chFmt); + } + else if ( xFrac == 0 ) + { + m_if.filterVer(compID, ref, refStride, dst, dstStride, cxWidth, cxHeight, yFrac, true, !bi, chFmt); + } + else + { + Int tmpStride = m_filteredBlockTmp[0].getStride(compID); + Pel* tmp = m_filteredBlockTmp[0].getAddr(compID); + + const Int vFilterSize = isLuma(compID) ? NTAPS_LUMA : NTAPS_CHROMA; + + m_if.filterHor(compID, ref - ((vFilterSize>>1) -1)*refStride, refStride, tmp, tmpStride, cxWidth, cxHeight+vFilterSize-1, xFrac, false, chFmt); + m_if.filterVer(compID, tmp + ((vFilterSize>>1) -1)*tmpStride, tmpStride, dst, dstStride, cxWidth, cxHeight, yFrac, false, !bi, chFmt); + } +} + +Void TComPrediction::xWeightedAverage( TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, Int iRefIdx0, Int iRefIdx1, UInt uiPartIdx, Int iWidth, Int iHeight, TComYuv* pcYuvDst ) +{ + if( iRefIdx0 >= 0 && iRefIdx1 >= 0 ) + { + pcYuvDst->addAvg( pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight ); + } + else if ( iRefIdx0 >= 0 && iRefIdx1 < 0 ) + { + pcYuvSrc0->copyPartToPartYuv( pcYuvDst, uiPartIdx, iWidth, iHeight ); + } + else if ( iRefIdx0 < 0 && iRefIdx1 >= 0 ) + { + pcYuvSrc1->copyPartToPartYuv( pcYuvDst, uiPartIdx, iWidth, iHeight ); + } +} + +// AMVP +Void TComPrediction::getMvPredAMVP( TComDataCU* pcCU, UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, TComMv& rcMvPred ) +{ + AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo(); + + if( pcAMVPInfo->iN <= 1 ) + { + rcMvPred = pcAMVPInfo->m_acMvCand[0]; + + pcCU->setMVPIdxSubParts( 0, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + return; + } + + assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0); + rcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)]; + return; +} + +/** Function for deriving planar intra prediction. + * \param pSrc pointer to reconstructed sample array + * \param srcStride the stride of the reconstructed sample array + * \param rpDst reference to pointer for the prediction sample array + * \param dstStride the stride of the prediction sample array + * \param width the width of the block + * \param height the height of the block + * + * This function derives the prediction samples for planar mode (intra coding). + */ +//NOTE: Bit-Limit - 24-bit source +Void TComPrediction::xPredIntraPlanar( const Pel* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height, ChannelType channelType, ChromaFormat format ) +{ + assert(width <= height); + + Int leftColumn[MAX_CU_SIZE+1], topRow[MAX_CU_SIZE+1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE]; + UInt shift1Dhor = g_aucConvertToBit[ width ] + 2; + UInt shift1Dver = g_aucConvertToBit[ height ] + 2; + + // Get left and above reference column and row + for(Int k=0;k>topRowShift); + rpDst[y*dstStride+x] = ( horPred + vertPred ) >> (shift1Dhor+1); + } + } +} + +/** Function for filtering intra DC predictor. + * \param pSrc pointer to reconstructed sample array + * \param iSrcStride the stride of the reconstructed sample array + * \param rpDst reference to pointer for the prediction sample array + * \param iDstStride the stride of the prediction sample array + * \param iWidth the width of the block + * \param iHeight the height of the block + * + * This function performs filtering left and top edges of the prediction samples for DC mode (intra coding). + */ +Void TComPrediction::xDCPredFiltering( const Pel* pSrc, Int iSrcStride, Pel* pDst, Int iDstStride, Int iWidth, Int iHeight, ChannelType channelType ) +{ + Int x, y, iDstStride2, iSrcStride2; + + if (isLuma(channelType) && (iWidth <= MAXIMUM_INTRA_FILTERED_WIDTH) && (iHeight <= MAXIMUM_INTRA_FILTERED_HEIGHT)) + { + //top-left + pDst[0] = (Pel)((pSrc[-iSrcStride] + pSrc[-1] + 2 * pDst[0] + 2) >> 2); + + //top row (vertical filter) + for ( x = 1; x < iWidth; x++ ) + { + pDst[x] = (Pel)((pSrc[x - iSrcStride] + 3 * pDst[x] + 2) >> 2); + } + + //left column (horizontal filter) + for ( y = 1, iDstStride2 = iDstStride, iSrcStride2 = iSrcStride-1; y < iHeight; y++, iDstStride2+=iDstStride, iSrcStride2+=iSrcStride ) + { + pDst[iDstStride2] = (Pel)((pSrc[iSrcStride2] + 3 * pDst[iDstStride2] + 2) >> 2); + } + } + + return; +} + +/* Static member function */ +Bool TComPrediction::UseDPCMForFirstPassIntraEstimation(TComTU &rTu, const UInt uiDirMode) +{ + return (rTu.getCU()->isRDPCMEnabled(rTu.GetAbsPartIdxTU()) ) && + rTu.getCU()->getCUTransquantBypass(rTu.GetAbsPartIdxTU()) && + (uiDirMode==HOR_IDX || uiDirMode==VER_IDX); +} + +//! \} diff --git a/jctvc/TLibCommon/TComPrediction.h b/jctvc/TLibCommon/TComPrediction.h new file mode 100644 index 0000000..2433cac --- /dev/null +++ b/jctvc/TLibCommon/TComPrediction.h @@ -0,0 +1,143 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComPrediction.h + \brief prediction class (header) +*/ + +#ifndef __TCOMPREDICTION__ +#define __TCOMPREDICTION__ + + +// Include files +#include "TComPic.h" +#include "TComMotionInfo.h" +#include "TComPattern.h" +#include "TComTrQuant.h" +#include "TComInterpolationFilter.h" +#include "TComWeightPrediction.h" + +class TComTU; // forward declaration + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// prediction class +typedef enum PRED_BUF_E +{ + PRED_BUF_UNFILTERED=0, + PRED_BUF_FILTERED=1, + NUM_PRED_BUF=2 +} PRED_BUF; + +static const UInt MAX_INTRA_FILTER_DEPTHS=5; + +class TComPrediction : public TComWeightPrediction +{ +private: + static const UChar m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS]; + +protected: + Pel* m_piYuvExt[MAX_NUM_COMPONENT][NUM_PRED_BUF]; + Int m_iYuvExtSize; + + TComYuv m_acYuvPred[NUM_REF_PIC_LIST_01]; + TComYuv m_cYuvPredTemp; + TComYuv m_filteredBlock[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS]; + TComYuv m_filteredBlockTmp[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS]; + + TComInterpolationFilter m_if; + + Pel* m_pLumaRecBuffer; ///< array for downsampled reconstructed luma sample + Int m_iLumaRecStride; ///< stride of #m_pLumaRecBuffer array + + Void xPredIntraAng ( Int bitDepth, const Pel* pSrc, Int srcStride, Pel* pDst, Int dstStride, UInt width, UInt height, ChannelType channelType, ChromaFormat format, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, const Bool bEnableEdgeFilters ); + Void xPredIntraPlanar ( const Pel* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height, ChannelType channelType, ChromaFormat format ); + + // motion compensation functions + Void xPredInterUni ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, RefPicList eRefPicList, TComYuv* pcYuvPred, Bool bi=false ); + Void xPredInterBi ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, TComYuv* pcYuvPred ); + Void xPredInterBlk(const ComponentID compID, TComDataCU *cu, TComPicYuv *refPic, UInt partAddr, TComMv *mv, Int width, Int height, TComYuv *dstPic, Bool bi ); + Void xWeightedAverage ( TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, Int iRefIdx0, Int iRefIdx1, UInt uiPartAddr, Int iWidth, Int iHeight, TComYuv* pcYuvDst ); + + Void xGetLLSPrediction ( const Pel* pSrc0, Int iSrcStride, Pel* pDst0, Int iDstStride, UInt uiWidth, UInt uiHeight, UInt uiExt0, const ChromaFormat chFmt DEBUG_STRING_FN_DECLARE(sDebug) ); + + Void xDCPredFiltering( const Pel* pSrc, Int iSrcStride, Pel* pDst, Int iDstStride, Int iWidth, Int iHeight, ChannelType channelType ); + Bool xCheckIdenticalMotion ( TComDataCU* pcCU, UInt PartAddr); + Void destroy(); + +public: + TComPrediction(); + virtual ~TComPrediction(); + + Void initTempBuff(ChromaFormat chromaFormatIDC); + + ChromaFormat getChromaFormat() const { return m_cYuvPredTemp.getChromaFormat(); } + + // inter + Void motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList = REF_PIC_LIST_X, Int iPartIdx = -1 ); + + // motion vector prediction + Void getMvPredAMVP ( TComDataCU* pcCU, UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, TComMv& rcMvPred ); + + // Angular Intra + Void predIntraAng ( const ComponentID compID, UInt uiDirMode, Pel *piOrg /* Will be null for decoding */, UInt uiOrgStride, Pel* piPred, UInt uiStride, TComTU &rTu, Bool bAbove, Bool bLeft, const Bool bUseFilteredPredSamples, const Bool bUseLosslessDPCM = false ); + + Pel predIntraGetPredValDC ( const Pel* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight, ChannelType channelType, ChromaFormat format, Bool bAbove, Bool bLeft ); + + Pel* getPredictorPtr ( const ComponentID compID, const Bool bUseFilteredPredictions ) + { + return m_piYuvExt[compID][bUseFilteredPredictions?PRED_BUF_FILTERED:PRED_BUF_UNFILTERED]; + } + + // This function is actually still in TComPattern.cpp + /// set parameters from CU data for accessing ADI data + Void initAdiPatternChType ( TComTU &rTu, + Bool& bAbove, + Bool& bLeft, + const ComponentID compID, const Bool bFilterRefSamples + DEBUG_STRING_FN_DECLARE(sDebug) + ); + + static Bool filteringIntraReferenceSamples(const ComponentID compID, UInt uiDirMode, UInt uiTuChWidth, UInt uiTuChHeight, const ChromaFormat chFmt, const Bool intraReferenceSmoothingDisabled); + + static Bool UseDPCMForFirstPassIntraEstimation(TComTU &rTu, const UInt uiDirMode); +}; + +//! \} + +#endif // __TCOMPREDICTION__ diff --git a/jctvc/TLibCommon/TComRdCost.cpp b/jctvc/TLibCommon/TComRdCost.cpp new file mode 100644 index 0000000..61232cc --- /dev/null +++ b/jctvc/TLibCommon/TComRdCost.cpp @@ -0,0 +1,1606 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRdCost.cpp + \brief RD cost computation class +*/ + +#include +#include +#include "TComRom.h" +#include "TComRdCost.h" + +//! \ingroup TLibCommon +//! \{ + +TComRdCost::TComRdCost() +{ + init(); +} + +TComRdCost::~TComRdCost() +{ +} + +// Calculate RD functions +Double TComRdCost::calcRdCost( UInt uiBits, Distortion uiDistortion, Bool bFlag, DFunc eDFunc ) +{ + Double dRdCost = 0.0; + Double dLambda = 0.0; + + switch ( eDFunc ) + { + case DF_SSE: + assert(0); + break; + case DF_SAD: +#if RExt__HIGH_BIT_DEPTH_SUPPORT + dLambda = m_dLambdaMotionSAD[0]; // 0 is valid, because for lossless blocks, the cost equation is modified to compensate. +#else + dLambda = (Double)m_uiLambdaMotionSAD[0]; // 0 is valid, because for lossless blocks, the cost equation is modified to compensate. +#endif + break; + case DF_DEFAULT: + dLambda = m_dLambda; + break; + case DF_SSE_FRAME: + dLambda = m_dFrameLambda; + break; + default: + assert (0); + break; + } + + if (bFlag) //NOTE: this "bFlag" is never true + { + // Intra8x8, Intra4x4 Block only... + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = (Double(uiDistortion) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = (((Double)uiDistortion) + ((Double)uiBits * dLambda)); + } + } + else + { + if (eDFunc == DF_SAD) + { + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = ((Double(uiDistortion) * 65536) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = floor(Double(uiDistortion) + (floor((Double(uiBits) * dLambda) + 0.5) / 65536.0)); + } + } + else + { + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = (Double(uiDistortion) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = floor(Double(uiDistortion) + (Double(uiBits) * dLambda) + 0.5); + } + } + } + + return dRdCost; +} + +Double TComRdCost::calcRdCost64( UInt64 uiBits, UInt64 uiDistortion, Bool bFlag, DFunc eDFunc ) +{ + Double dRdCost = 0.0; + Double dLambda = 0.0; + + switch ( eDFunc ) + { + case DF_SSE: + assert(0); + break; + case DF_SAD: +#if RExt__HIGH_BIT_DEPTH_SUPPORT + dLambda = m_dLambdaMotionSAD[0]; // 0 is valid, because for lossless blocks, the cost equation is modified to compensate. +#else + dLambda = (Double)m_uiLambdaMotionSAD[0]; // 0 is valid, because for lossless blocks, the cost equation is modified to compensate. +#endif + break; + case DF_DEFAULT: + dLambda = m_dLambda; + break; + case DF_SSE_FRAME: + dLambda = m_dFrameLambda; + break; + default: + assert (0); + break; + } + + if (bFlag) //NOTE: this "bFlag" is never true + { + // Intra8x8, Intra4x4 Block only... + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = (Double(uiDistortion) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = (((Double)(Int64)uiDistortion) + ((Double)(Int64)uiBits * dLambda)); + } + } + else + { + if (eDFunc == DF_SAD) + { + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = ((Double(uiDistortion) * 65536) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = floor(Double(uiDistortion) + (floor((Double(uiBits) * dLambda) + 0.5) / 65536.0)); + } + } + else + { + if (m_costMode != COST_STANDARD_LOSSY) + { + dRdCost = (Double(uiDistortion) / dLambda) + Double(uiBits); // all lossless costs would have uiDistortion=0, and therefore this cost function can be used. + } + else + { + dRdCost = floor(Double(uiDistortion) + (Double(uiBits) * dLambda) + 0.5); + } + } + } + + return dRdCost; +} + +Void TComRdCost::setLambda( Double dLambda ) +{ + m_dLambda = dLambda; + m_sqrtLambda = sqrt(m_dLambda); +#if RExt__HIGH_BIT_DEPTH_SUPPORT + m_dLambdaMotionSAD[0] = 65536.0 * m_sqrtLambda; + m_dLambdaMotionSSE[0] = 65536.0 * m_dLambda; +#if FULL_NBIT + dLambda = 0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12) / 3.0)); +#else + dLambda = 0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12 - 6 * (g_bitDepth[CHANNEL_TYPE_LUMA] - 8)) / 3.0)); +#endif + m_dLambdaMotionSAD[1] = 65536.0 * sqrt(dLambda); + m_dLambdaMotionSSE[1] = 65536.0 * dLambda; +#else + m_uiLambdaMotionSAD[0] = (UInt)floor(65536.0 * m_sqrtLambda); + m_uiLambdaMotionSSE[0] = (UInt)floor(65536.0 * m_dLambda ); +#if FULL_NBIT + dLambda = 0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12) / 3.0)); +#else + dLambda = 0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12 - 6 * (g_bitDepth[CHANNEL_TYPE_LUMA] - 8)) / 3.0)); +#endif + m_uiLambdaMotionSAD[1] = (UInt)floor(65536.0 * sqrt(dLambda)); + m_uiLambdaMotionSSE[1] = (UInt)floor(65536.0 * dLambda ); +#endif +} + + +// Initalize Function Pointer by [eDFunc] +Void TComRdCost::init() +{ + m_afpDistortFunc[DF_DEFAULT] = NULL; // for DF_DEFAULT + + m_afpDistortFunc[DF_SSE ] = TComRdCost::xGetSSE; + m_afpDistortFunc[DF_SSE4 ] = TComRdCost::xGetSSE4; + m_afpDistortFunc[DF_SSE8 ] = TComRdCost::xGetSSE8; + m_afpDistortFunc[DF_SSE16 ] = TComRdCost::xGetSSE16; + m_afpDistortFunc[DF_SSE32 ] = TComRdCost::xGetSSE32; + m_afpDistortFunc[DF_SSE64 ] = TComRdCost::xGetSSE64; + m_afpDistortFunc[DF_SSE16N ] = TComRdCost::xGetSSE16N; + + m_afpDistortFunc[DF_SAD ] = TComRdCost::xGetSAD; + m_afpDistortFunc[DF_SAD4 ] = TComRdCost::xGetSAD4; + m_afpDistortFunc[DF_SAD8 ] = TComRdCost::xGetSAD8; + m_afpDistortFunc[DF_SAD16 ] = TComRdCost::xGetSAD16; + m_afpDistortFunc[DF_SAD32 ] = TComRdCost::xGetSAD32; + m_afpDistortFunc[DF_SAD64 ] = TComRdCost::xGetSAD64; + m_afpDistortFunc[DF_SAD16N ] = TComRdCost::xGetSAD16N; + + m_afpDistortFunc[DF_SADS ] = TComRdCost::xGetSAD; + m_afpDistortFunc[DF_SADS4 ] = TComRdCost::xGetSAD4; + m_afpDistortFunc[DF_SADS8 ] = TComRdCost::xGetSAD8; + m_afpDistortFunc[DF_SADS16 ] = TComRdCost::xGetSAD16; + m_afpDistortFunc[DF_SADS32 ] = TComRdCost::xGetSAD32; + m_afpDistortFunc[DF_SADS64 ] = TComRdCost::xGetSAD64; + m_afpDistortFunc[DF_SADS16N] = TComRdCost::xGetSAD16N; + +#if AMP_SAD + m_afpDistortFunc[DF_SAD12 ] = TComRdCost::xGetSAD12; + m_afpDistortFunc[DF_SAD24 ] = TComRdCost::xGetSAD24; + m_afpDistortFunc[DF_SAD48 ] = TComRdCost::xGetSAD48; + + m_afpDistortFunc[DF_SADS12 ] = TComRdCost::xGetSAD12; + m_afpDistortFunc[DF_SADS24 ] = TComRdCost::xGetSAD24; + m_afpDistortFunc[DF_SADS48 ] = TComRdCost::xGetSAD48; +#endif + m_afpDistortFunc[DF_HADS ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS4 ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS8 ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS16 ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS32 ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS64 ] = TComRdCost::xGetHADs; + m_afpDistortFunc[DF_HADS16N] = TComRdCost::xGetHADs; + + m_costMode = COST_STANDARD_LOSSY; + +#if RExt__HIGH_BIT_DEPTH_SUPPORT + m_dCost = 0; +#else + m_uiCost = 0; +#endif + m_iCostScale = 0; +} + +UInt TComRdCost::xGetComponentBits( Int iVal ) +{ + UInt uiLength = 1; + UInt uiTemp = ( iVal <= 0) ? (-iVal<<1)+1: (iVal<<1); + + assert ( uiTemp ); + + while ( 1 != uiTemp ) + { + uiTemp >>= 1; + uiLength += 2; + } + + return uiLength; +} + +Void TComRdCost::setDistParam( UInt uiBlkWidth, UInt uiBlkHeight, DFunc eDFunc, DistParam& rcDistParam ) +{ + // set Block Width / Height + rcDistParam.iCols = uiBlkWidth; + rcDistParam.iRows = uiBlkHeight; + rcDistParam.DistFunc = m_afpDistortFunc[eDFunc + g_aucConvertToBit[ rcDistParam.iCols ] + 1 ]; + + // initialize + rcDistParam.iSubShift = 0; +} + +// Setting the Distortion Parameter for Inter (ME) +Void TComRdCost::setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, DistParam& rcDistParam ) +{ + // set Original & Curr Pointer / Stride + rcDistParam.pOrg = pcPatternKey->getROIY(); + rcDistParam.pCur = piRefY; + + rcDistParam.iStrideOrg = pcPatternKey->getPatternLStride(); + rcDistParam.iStrideCur = iRefStride; + + // set Block Width / Height + rcDistParam.iCols = pcPatternKey->getROIYWidth(); + rcDistParam.iRows = pcPatternKey->getROIYHeight(); + rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD + g_aucConvertToBit[ rcDistParam.iCols ] + 1 ]; + +#if AMP_SAD + if (rcDistParam.iCols == 12) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD12]; + } + else if (rcDistParam.iCols == 24) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD24]; + } + else if (rcDistParam.iCols == 48) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD48]; + } +#endif + + // initialize + rcDistParam.iSubShift = 0; +} + +// Setting the Distortion Parameter for Inter (subpel ME with step) +Void TComRdCost::setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, Int iStep, DistParam& rcDistParam, Bool bHADME ) +{ + // set Original & Curr Pointer / Stride + rcDistParam.pOrg = pcPatternKey->getROIY(); + rcDistParam.pCur = piRefY; + + rcDistParam.iStrideOrg = pcPatternKey->getPatternLStride(); + rcDistParam.iStrideCur = iRefStride * iStep; + + // set Step for interpolated buffer + rcDistParam.iStep = iStep; + + // set Block Width / Height + rcDistParam.iCols = pcPatternKey->getROIYWidth(); + rcDistParam.iRows = pcPatternKey->getROIYHeight(); + + // set distortion function + if ( !bHADME ) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SADS + g_aucConvertToBit[ rcDistParam.iCols ] + 1 ]; +#if AMP_SAD + if (rcDistParam.iCols == 12) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SADS12]; + } + else if (rcDistParam.iCols == 24) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SADS24]; + } + else if (rcDistParam.iCols == 48) + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_SADS48]; + } +#endif + } + else + { + rcDistParam.DistFunc = m_afpDistortFunc[DF_HADS + g_aucConvertToBit[ rcDistParam.iCols ] + 1 ]; + } + + // initialize + rcDistParam.iSubShift = 0; +} + +Void TComRdCost::setDistParam( DistParam& rcDP, Int bitDepth, Pel* p1, Int iStride1, Pel* p2, Int iStride2, Int iWidth, Int iHeight, Bool bHadamard ) +{ + rcDP.pOrg = p1; + rcDP.pCur = p2; + rcDP.iStrideOrg = iStride1; + rcDP.iStrideCur = iStride2; + rcDP.iCols = iWidth; + rcDP.iRows = iHeight; + rcDP.iStep = 1; + rcDP.iSubShift = 0; + rcDP.bitDepth = bitDepth; + rcDP.DistFunc = m_afpDistortFunc[ ( bHadamard ? DF_HADS : DF_SADS ) + g_aucConvertToBit[ iWidth ] + 1 ]; +} + +Distortion TComRdCost::calcHAD( Int bitDepth, Pel* pi0, Int iStride0, Pel* pi1, Int iStride1, Int iWidth, Int iHeight ) +{ + Distortion uiSum = 0; + Int x, y; + + if ( ( (iWidth % 8) == 0 ) && ( (iHeight % 8) == 0 ) ) + { + for ( y=0; y> DISTORTION_PRECISION_ADJUSTMENT(bitDepth-8) ); +} + +Distortion TComRdCost::getDistPart( Int bitDepth, Pel* piCur, Int iCurStride, Pel* piOrg, Int iOrgStride, UInt uiBlkWidth, UInt uiBlkHeight, const ComponentID compID, DFunc eDFunc ) +{ + DistParam cDtParam; + setDistParam( uiBlkWidth, uiBlkHeight, eDFunc, cDtParam ); + cDtParam.pOrg = piOrg; + cDtParam.pCur = piCur; + cDtParam.iStrideOrg = iOrgStride; + cDtParam.iStrideCur = iCurStride; + cDtParam.iStep = 1; + + cDtParam.bApplyWeight = false; + cDtParam.compIdx = MAX_NUM_COMPONENT; // just for assert: to be sure it was set before use + cDtParam.bitDepth = bitDepth; + + if (isChroma(compID)) + { + return ((Distortion) (m_distortionWeight[compID] * cDtParam.DistFunc( &cDtParam ))); + } + else + { + return cDtParam.DistFunc( &cDtParam ); + } +} + +// ==================================================================================================================== +// Distortion functions +// ==================================================================================================================== + +// -------------------------------------------------------------------------------------------------------------------- +// SAD +// -------------------------------------------------------------------------------------------------------------------- + +Distortion TComRdCost::xGetSAD( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iCols = pcDtParam->iCols; + Int iStrideCur = pcDtParam->iStrideCur; + Int iStrideOrg = pcDtParam->iStrideOrg; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-- ) + { + for (Int n = 0; n < iCols; n++ ) + { + uiSum += abs( piOrg[n] - piCur[n] ); + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +Distortion TComRdCost::xGetSAD4( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +Distortion TComRdCost::xGetSAD8( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +Distortion TComRdCost::xGetSAD16( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + uiSum += abs( piOrg[12] - piCur[12] ); + uiSum += abs( piOrg[13] - piCur[13] ); + uiSum += abs( piOrg[14] - piCur[14] ); + uiSum += abs( piOrg[15] - piCur[15] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +#if AMP_SAD +Distortion TComRdCost::xGetSAD12( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} +#endif + +Distortion TComRdCost::xGetSAD16N( DistParam* pcDtParam ) +{ + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iCols = pcDtParam->iCols; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + for (Int n = 0; n < iCols; n+=16 ) + { + uiSum += abs( piOrg[n+ 0] - piCur[n+ 0] ); + uiSum += abs( piOrg[n+ 1] - piCur[n+ 1] ); + uiSum += abs( piOrg[n+ 2] - piCur[n+ 2] ); + uiSum += abs( piOrg[n+ 3] - piCur[n+ 3] ); + uiSum += abs( piOrg[n+ 4] - piCur[n+ 4] ); + uiSum += abs( piOrg[n+ 5] - piCur[n+ 5] ); + uiSum += abs( piOrg[n+ 6] - piCur[n+ 6] ); + uiSum += abs( piOrg[n+ 7] - piCur[n+ 7] ); + uiSum += abs( piOrg[n+ 8] - piCur[n+ 8] ); + uiSum += abs( piOrg[n+ 9] - piCur[n+ 9] ); + uiSum += abs( piOrg[n+10] - piCur[n+10] ); + uiSum += abs( piOrg[n+11] - piCur[n+11] ); + uiSum += abs( piOrg[n+12] - piCur[n+12] ); + uiSum += abs( piOrg[n+13] - piCur[n+13] ); + uiSum += abs( piOrg[n+14] - piCur[n+14] ); + uiSum += abs( piOrg[n+15] - piCur[n+15] ); + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +Distortion TComRdCost::xGetSAD32( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + uiSum += abs( piOrg[12] - piCur[12] ); + uiSum += abs( piOrg[13] - piCur[13] ); + uiSum += abs( piOrg[14] - piCur[14] ); + uiSum += abs( piOrg[15] - piCur[15] ); + uiSum += abs( piOrg[16] - piCur[16] ); + uiSum += abs( piOrg[17] - piCur[17] ); + uiSum += abs( piOrg[18] - piCur[18] ); + uiSum += abs( piOrg[19] - piCur[19] ); + uiSum += abs( piOrg[20] - piCur[20] ); + uiSum += abs( piOrg[21] - piCur[21] ); + uiSum += abs( piOrg[22] - piCur[22] ); + uiSum += abs( piOrg[23] - piCur[23] ); + uiSum += abs( piOrg[24] - piCur[24] ); + uiSum += abs( piOrg[25] - piCur[25] ); + uiSum += abs( piOrg[26] - piCur[26] ); + uiSum += abs( piOrg[27] - piCur[27] ); + uiSum += abs( piOrg[28] - piCur[28] ); + uiSum += abs( piOrg[29] - piCur[29] ); + uiSum += abs( piOrg[30] - piCur[30] ); + uiSum += abs( piOrg[31] - piCur[31] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +#if AMP_SAD +Distortion TComRdCost::xGetSAD24( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + uiSum += abs( piOrg[12] - piCur[12] ); + uiSum += abs( piOrg[13] - piCur[13] ); + uiSum += abs( piOrg[14] - piCur[14] ); + uiSum += abs( piOrg[15] - piCur[15] ); + uiSum += abs( piOrg[16] - piCur[16] ); + uiSum += abs( piOrg[17] - piCur[17] ); + uiSum += abs( piOrg[18] - piCur[18] ); + uiSum += abs( piOrg[19] - piCur[19] ); + uiSum += abs( piOrg[20] - piCur[20] ); + uiSum += abs( piOrg[21] - piCur[21] ); + uiSum += abs( piOrg[22] - piCur[22] ); + uiSum += abs( piOrg[23] - piCur[23] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +#endif + +Distortion TComRdCost::xGetSAD64( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + uiSum += abs( piOrg[12] - piCur[12] ); + uiSum += abs( piOrg[13] - piCur[13] ); + uiSum += abs( piOrg[14] - piCur[14] ); + uiSum += abs( piOrg[15] - piCur[15] ); + uiSum += abs( piOrg[16] - piCur[16] ); + uiSum += abs( piOrg[17] - piCur[17] ); + uiSum += abs( piOrg[18] - piCur[18] ); + uiSum += abs( piOrg[19] - piCur[19] ); + uiSum += abs( piOrg[20] - piCur[20] ); + uiSum += abs( piOrg[21] - piCur[21] ); + uiSum += abs( piOrg[22] - piCur[22] ); + uiSum += abs( piOrg[23] - piCur[23] ); + uiSum += abs( piOrg[24] - piCur[24] ); + uiSum += abs( piOrg[25] - piCur[25] ); + uiSum += abs( piOrg[26] - piCur[26] ); + uiSum += abs( piOrg[27] - piCur[27] ); + uiSum += abs( piOrg[28] - piCur[28] ); + uiSum += abs( piOrg[29] - piCur[29] ); + uiSum += abs( piOrg[30] - piCur[30] ); + uiSum += abs( piOrg[31] - piCur[31] ); + uiSum += abs( piOrg[32] - piCur[32] ); + uiSum += abs( piOrg[33] - piCur[33] ); + uiSum += abs( piOrg[34] - piCur[34] ); + uiSum += abs( piOrg[35] - piCur[35] ); + uiSum += abs( piOrg[36] - piCur[36] ); + uiSum += abs( piOrg[37] - piCur[37] ); + uiSum += abs( piOrg[38] - piCur[38] ); + uiSum += abs( piOrg[39] - piCur[39] ); + uiSum += abs( piOrg[40] - piCur[40] ); + uiSum += abs( piOrg[41] - piCur[41] ); + uiSum += abs( piOrg[42] - piCur[42] ); + uiSum += abs( piOrg[43] - piCur[43] ); + uiSum += abs( piOrg[44] - piCur[44] ); + uiSum += abs( piOrg[45] - piCur[45] ); + uiSum += abs( piOrg[46] - piCur[46] ); + uiSum += abs( piOrg[47] - piCur[47] ); + uiSum += abs( piOrg[48] - piCur[48] ); + uiSum += abs( piOrg[49] - piCur[49] ); + uiSum += abs( piOrg[50] - piCur[50] ); + uiSum += abs( piOrg[51] - piCur[51] ); + uiSum += abs( piOrg[52] - piCur[52] ); + uiSum += abs( piOrg[53] - piCur[53] ); + uiSum += abs( piOrg[54] - piCur[54] ); + uiSum += abs( piOrg[55] - piCur[55] ); + uiSum += abs( piOrg[56] - piCur[56] ); + uiSum += abs( piOrg[57] - piCur[57] ); + uiSum += abs( piOrg[58] - piCur[58] ); + uiSum += abs( piOrg[59] - piCur[59] ); + uiSum += abs( piOrg[60] - piCur[60] ); + uiSum += abs( piOrg[61] - piCur[61] ); + uiSum += abs( piOrg[62] - piCur[62] ); + uiSum += abs( piOrg[63] - piCur[63] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +#if AMP_SAD +Distortion TComRdCost::xGetSAD48( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSADw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iSubShift = pcDtParam->iSubShift; + Int iSubStep = ( 1 << iSubShift ); + Int iStrideCur = pcDtParam->iStrideCur*iSubStep; + Int iStrideOrg = pcDtParam->iStrideOrg*iSubStep; + + Distortion uiSum = 0; + + for( ; iRows != 0; iRows-=iSubStep ) + { + uiSum += abs( piOrg[0] - piCur[0] ); + uiSum += abs( piOrg[1] - piCur[1] ); + uiSum += abs( piOrg[2] - piCur[2] ); + uiSum += abs( piOrg[3] - piCur[3] ); + uiSum += abs( piOrg[4] - piCur[4] ); + uiSum += abs( piOrg[5] - piCur[5] ); + uiSum += abs( piOrg[6] - piCur[6] ); + uiSum += abs( piOrg[7] - piCur[7] ); + uiSum += abs( piOrg[8] - piCur[8] ); + uiSum += abs( piOrg[9] - piCur[9] ); + uiSum += abs( piOrg[10] - piCur[10] ); + uiSum += abs( piOrg[11] - piCur[11] ); + uiSum += abs( piOrg[12] - piCur[12] ); + uiSum += abs( piOrg[13] - piCur[13] ); + uiSum += abs( piOrg[14] - piCur[14] ); + uiSum += abs( piOrg[15] - piCur[15] ); + uiSum += abs( piOrg[16] - piCur[16] ); + uiSum += abs( piOrg[17] - piCur[17] ); + uiSum += abs( piOrg[18] - piCur[18] ); + uiSum += abs( piOrg[19] - piCur[19] ); + uiSum += abs( piOrg[20] - piCur[20] ); + uiSum += abs( piOrg[21] - piCur[21] ); + uiSum += abs( piOrg[22] - piCur[22] ); + uiSum += abs( piOrg[23] - piCur[23] ); + uiSum += abs( piOrg[24] - piCur[24] ); + uiSum += abs( piOrg[25] - piCur[25] ); + uiSum += abs( piOrg[26] - piCur[26] ); + uiSum += abs( piOrg[27] - piCur[27] ); + uiSum += abs( piOrg[28] - piCur[28] ); + uiSum += abs( piOrg[29] - piCur[29] ); + uiSum += abs( piOrg[30] - piCur[30] ); + uiSum += abs( piOrg[31] - piCur[31] ); + uiSum += abs( piOrg[32] - piCur[32] ); + uiSum += abs( piOrg[33] - piCur[33] ); + uiSum += abs( piOrg[34] - piCur[34] ); + uiSum += abs( piOrg[35] - piCur[35] ); + uiSum += abs( piOrg[36] - piCur[36] ); + uiSum += abs( piOrg[37] - piCur[37] ); + uiSum += abs( piOrg[38] - piCur[38] ); + uiSum += abs( piOrg[39] - piCur[39] ); + uiSum += abs( piOrg[40] - piCur[40] ); + uiSum += abs( piOrg[41] - piCur[41] ); + uiSum += abs( piOrg[42] - piCur[42] ); + uiSum += abs( piOrg[43] - piCur[43] ); + uiSum += abs( piOrg[44] - piCur[44] ); + uiSum += abs( piOrg[45] - piCur[45] ); + uiSum += abs( piOrg[46] - piCur[46] ); + uiSum += abs( piOrg[47] - piCur[47] ); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + uiSum <<= iSubShift; + return ( uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// SSE +// -------------------------------------------------------------------------------------------------------------------- + +Distortion TComRdCost::xGetSSE( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iCols = pcDtParam->iCols; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + for (Int n = 0; n < iCols; n++ ) + { + iTemp = piOrg[n ] - piCur[n ]; + uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE4( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + assert( pcDtParam->iCols == 4 ); + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + + iTemp = piOrg[0] - piCur[0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[1] - piCur[1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[2] - piCur[2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[3] - piCur[3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE8( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + assert( pcDtParam->iCols == 8 ); + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + iTemp = piOrg[0] - piCur[0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[1] - piCur[1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[2] - piCur[2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[3] - piCur[3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[4] - piCur[4]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[5] - piCur[5]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[6] - piCur[6]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[7] - piCur[7]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE16( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + assert( pcDtParam->iCols == 16 ); + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + + iTemp = piOrg[ 0] - piCur[ 0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 1] - piCur[ 1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 2] - piCur[ 2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 3] - piCur[ 3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 4] - piCur[ 4]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 5] - piCur[ 5]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 6] - piCur[ 6]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 7] - piCur[ 7]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 8] - piCur[ 8]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 9] - piCur[ 9]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[10] - piCur[10]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[11] - piCur[11]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[12] - piCur[12]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[13] - piCur[13]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[14] - piCur[14]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[15] - piCur[15]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE16N( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iCols = pcDtParam->iCols; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + for (Int n = 0; n < iCols; n+=16 ) + { + + iTemp = piOrg[n+ 0] - piCur[n+ 0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 1] - piCur[n+ 1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 2] - piCur[n+ 2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 3] - piCur[n+ 3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 4] - piCur[n+ 4]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 5] - piCur[n+ 5]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 6] - piCur[n+ 6]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 7] - piCur[n+ 7]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 8] - piCur[n+ 8]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+ 9] - piCur[n+ 9]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+10] - piCur[n+10]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+11] - piCur[n+11]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+12] - piCur[n+12]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+13] - piCur[n+13]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+14] - piCur[n+14]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[n+15] - piCur[n+15]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE32( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + assert( pcDtParam->iCols == 32 ); + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + + iTemp = piOrg[ 0] - piCur[ 0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 1] - piCur[ 1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 2] - piCur[ 2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 3] - piCur[ 3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 4] - piCur[ 4]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 5] - piCur[ 5]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 6] - piCur[ 6]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 7] - piCur[ 7]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 8] - piCur[ 8]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 9] - piCur[ 9]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[10] - piCur[10]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[11] - piCur[11]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[12] - piCur[12]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[13] - piCur[13]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[14] - piCur[14]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[15] - piCur[15]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[16] - piCur[16]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[17] - piCur[17]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[18] - piCur[18]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[19] - piCur[19]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[20] - piCur[20]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[21] - piCur[21]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[22] - piCur[22]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[23] - piCur[23]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[24] - piCur[24]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[25] - piCur[25]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[26] - piCur[26]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[27] - piCur[27]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[28] - piCur[28]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[29] - piCur[29]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[30] - piCur[30]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[31] - piCur[31]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +Distortion TComRdCost::xGetSSE64( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + assert( pcDtParam->iCols == 64 ); + return TComRdCostWeightPrediction::xGetSSEw( pcDtParam ); + } + const Pel* piOrg = pcDtParam->pOrg; + const Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStrideCur = pcDtParam->iStrideCur; + + Distortion uiSum = 0; + UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Intermediate_Int iTemp; + + for( ; iRows != 0; iRows-- ) + { + iTemp = piOrg[ 0] - piCur[ 0]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 1] - piCur[ 1]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 2] - piCur[ 2]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 3] - piCur[ 3]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 4] - piCur[ 4]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 5] - piCur[ 5]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 6] - piCur[ 6]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 7] - piCur[ 7]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 8] - piCur[ 8]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[ 9] - piCur[ 9]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[10] - piCur[10]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[11] - piCur[11]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[12] - piCur[12]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[13] - piCur[13]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[14] - piCur[14]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[15] - piCur[15]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[16] - piCur[16]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[17] - piCur[17]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[18] - piCur[18]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[19] - piCur[19]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[20] - piCur[20]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[21] - piCur[21]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[22] - piCur[22]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[23] - piCur[23]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[24] - piCur[24]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[25] - piCur[25]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[26] - piCur[26]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[27] - piCur[27]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[28] - piCur[28]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[29] - piCur[29]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[30] - piCur[30]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[31] - piCur[31]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[32] - piCur[32]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[33] - piCur[33]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[34] - piCur[34]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[35] - piCur[35]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[36] - piCur[36]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[37] - piCur[37]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[38] - piCur[38]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[39] - piCur[39]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[40] - piCur[40]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[41] - piCur[41]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[42] - piCur[42]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[43] - piCur[43]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[44] - piCur[44]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[45] - piCur[45]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[46] - piCur[46]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[47] - piCur[47]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[48] - piCur[48]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[49] - piCur[49]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[50] - piCur[50]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[51] - piCur[51]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[52] - piCur[52]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[53] - piCur[53]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[54] - piCur[54]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[55] - piCur[55]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[56] - piCur[56]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[57] - piCur[57]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[58] - piCur[58]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[59] - piCur[59]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[60] - piCur[60]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[61] - piCur[61]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[62] - piCur[62]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + iTemp = piOrg[63] - piCur[63]; uiSum += Distortion(( iTemp * iTemp ) >> uiShift); + + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + return ( uiSum ); +} + +// -------------------------------------------------------------------------------------------------------------------- +// HADAMARD with step (used in fractional search) +// -------------------------------------------------------------------------------------------------------------------- + +Distortion TComRdCost::xCalcHADs2x2( Pel *piOrg, Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + Distortion satd = 0; + TCoeff diff[4], m[4]; + assert( iStep == 1 ); + diff[0] = piOrg[0 ] - piCur[0]; + diff[1] = piOrg[1 ] - piCur[1]; + diff[2] = piOrg[iStrideOrg ] - piCur[0 + iStrideCur]; + diff[3] = piOrg[iStrideOrg + 1] - piCur[1 + iStrideCur]; + m[0] = diff[0] + diff[2]; + m[1] = diff[1] + diff[3]; + m[2] = diff[0] - diff[2]; + m[3] = diff[1] - diff[3]; + + satd += abs(m[0] + m[1]); + satd += abs(m[0] - m[1]); + satd += abs(m[2] + m[3]); + satd += abs(m[2] - m[3]); + + return satd; +} + +Distortion TComRdCost::xCalcHADs4x4( Pel *piOrg, Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + Int k; + Distortion satd = 0; + TCoeff diff[16], m[16], d[16]; + + assert( iStep == 1 ); + for( k = 0; k < 16; k+=4 ) + { + diff[k+0] = piOrg[0] - piCur[0]; + diff[k+1] = piOrg[1] - piCur[1]; + diff[k+2] = piOrg[2] - piCur[2]; + diff[k+3] = piOrg[3] - piCur[3]; + + piCur += iStrideCur; + piOrg += iStrideOrg; + } + + /*===== 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]; + + for (k=0; k<16; ++k) + { + satd += abs(d[k]); + } + satd = ((satd+1)>>1); + + return satd; +} + +Distortion TComRdCost::xCalcHADs8x8( Pel *piOrg, Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + Int k, i, j, jj; + Distortion sad = 0; + TCoeff diff[64], m1[8][8], m2[8][8], m3[8][8]; + assert( iStep == 1 ); + for( k = 0; k < 64; k += 8 ) + { + diff[k+0] = piOrg[0] - piCur[0]; + diff[k+1] = piOrg[1] - piCur[1]; + diff[k+2] = piOrg[2] - piCur[2]; + diff[k+3] = piOrg[3] - piCur[3]; + diff[k+4] = piOrg[4] - piCur[4]; + diff[k+5] = piOrg[5] - piCur[5]; + diff[k+6] = piOrg[6] - piCur[6]; + diff[k+7] = piOrg[7] - piCur[7]; + + piCur += iStrideCur; + piOrg += iStrideOrg; + } + + //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 (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + sad += abs(m2[i][j]); + } + } + + sad=((sad+2)>>2); + + return sad; +} + + +Distortion TComRdCost::xGetHADs( DistParam* pcDtParam ) +{ + if ( pcDtParam->bApplyWeight ) + { + return TComRdCostWeightPrediction::xGetHADsw( pcDtParam ); + } + Pel* piOrg = pcDtParam->pOrg; + Pel* piCur = pcDtParam->pCur; + Int iRows = pcDtParam->iRows; + Int iCols = pcDtParam->iCols; + Int iStrideCur = pcDtParam->iStrideCur; + Int iStrideOrg = pcDtParam->iStrideOrg; + Int iStep = pcDtParam->iStep; + + Int x, y; + + Distortion uiSum = 0; + + if( ( iRows % 8 == 0) && (iCols % 8 == 0) ) + { + Int iOffsetOrg = iStrideOrg<<3; + Int iOffsetCur = iStrideCur<<3; + for ( y=0; y> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8) ); +} + +//! \} diff --git a/jctvc/TLibCommon/TComRdCost.h b/jctvc/TLibCommon/TComRdCost.h new file mode 100644 index 0000000..13fc70a --- /dev/null +++ b/jctvc/TLibCommon/TComRdCost.h @@ -0,0 +1,230 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRdCost.h + \brief RD cost computation classes (header) +*/ + +#ifndef __TCOMRDCOST__ +#define __TCOMRDCOST__ + + +#include "CommonDef.h" +#include "TComPattern.h" +#include "TComMv.h" + +#include "TComSlice.h" +#include "TComRdCostWeightPrediction.h" + +//! \ingroup TLibCommon +//! \{ + +class DistParam; +class TComPattern; + +// ==================================================================================================================== +// Type definition +// ==================================================================================================================== + +// for function pointer +typedef Distortion (*FpDistFunc) (DistParam*); // TODO: can this pointer be replaced with a reference? - there are no NULL checks on pointer. + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// distortion parameter class +class DistParam +{ +public: + Pel* pOrg; + Pel* pCur; + Int iStrideOrg; + Int iStrideCur; + Int iRows; + Int iCols; + Int iStep; + FpDistFunc DistFunc; + Int bitDepth; + + Bool bApplyWeight; // whether weighted prediction is used or not + WPScalingParam *wpCur; // weighted prediction scaling parameters for current ref + ComponentID compIdx; + + // (vertical) subsampling shift (for reducing complexity) + // - 0 = no subsampling, 1 = even rows, 2 = every 4th, etc. + Int iSubShift; + + DistParam() + { + pOrg = NULL; + pCur = NULL; + iStrideOrg = 0; + iStrideCur = 0; + iRows = 0; + iCols = 0; + iStep = 1; + DistFunc = NULL; + iSubShift = 0; + bitDepth = 0; + } +}; + +/// RD cost computation class +class TComRdCost +{ +private: + // for distortion + + FpDistFunc m_afpDistortFunc[DF_TOTAL_FUNCTIONS]; // [eDFunc] + CostMode m_costMode; + Double m_distortionWeight[MAX_NUM_COMPONENT]; // only chroma values are used. + Double m_dLambda; + Double m_sqrtLambda; +#if RExt__HIGH_BIT_DEPTH_SUPPORT + Double m_dLambdaMotionSAD[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; + Double m_dLambdaMotionSSE[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; +#else + UInt m_uiLambdaMotionSAD[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; + UInt m_uiLambdaMotionSSE[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; +#endif + Double m_dFrameLambda; + + // for motion cost + TComMv m_mvPredictor; +#if RExt__HIGH_BIT_DEPTH_SUPPORT + Double m_dCost; +#else + UInt m_uiCost; +#endif + Int m_iCostScale; + +public: + TComRdCost(); + virtual ~TComRdCost(); + + Double calcRdCost ( UInt uiBits, Distortion uiDistortion, Bool bFlag = false, DFunc eDFunc = DF_DEFAULT ); + Double calcRdCost64( UInt64 uiBits, UInt64 uiDistortion, Bool bFlag = false, DFunc eDFunc = DF_DEFAULT ); + + Void setDistortionWeight ( const ComponentID compID, const Double distortionWeight ) { m_distortionWeight[compID] = distortionWeight; } + Void setLambda ( Double dLambda ); + Void setFrameLambda ( Double dLambda ) { m_dFrameLambda = dLambda; } + + Double getSqrtLambda () { return m_sqrtLambda; } + + Double getLambda() { return m_dLambda; } + Double getChromaWeight () { return ((m_distortionWeight[COMPONENT_Cb] + m_distortionWeight[COMPONENT_Cr]) / 2.0); } + + Void setCostMode(CostMode m ) { m_costMode = m; } + + // Distortion Functions + Void init(); + + Void setDistParam( UInt uiBlkWidth, UInt uiBlkHeight, DFunc eDFunc, DistParam& rcDistParam ); + Void setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, DistParam& rcDistParam ); + Void setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, Int iStep, DistParam& rcDistParam, Bool bHADME=false ); + Void setDistParam( DistParam& rcDP, Int bitDepth, Pel* p1, Int iStride1, Pel* p2, Int iStride2, Int iWidth, Int iHeight, Bool bHadamard = false ); + + Distortion calcHAD(Int bitDepth, Pel* pi0, Int iStride0, Pel* pi1, Int iStride1, Int iWidth, Int iHeight ); + + // for motion cost + UInt xGetComponentBits( Int iVal ); +#if RExt__HIGH_BIT_DEPTH_SUPPORT + Void getMotionCost( Bool bSad, Int iAdd, Bool bIsTransquantBypass ) { m_dCost = (bSad ? m_dLambdaMotionSAD[(bIsTransquantBypass && m_costMode==COST_MIXED_LOSSLESS_LOSSY_CODING) ?1:0] + iAdd : m_dLambdaMotionSSE[(bIsTransquantBypass && m_costMode==COST_MIXED_LOSSLESS_LOSSY_CODING)?1:0] + iAdd); } +#else + Void getMotionCost( Bool bSad, Int iAdd, Bool bIsTransquantBypass ) { m_uiCost = (bSad ? m_uiLambdaMotionSAD[(bIsTransquantBypass && m_costMode==COST_MIXED_LOSSLESS_LOSSY_CODING) ?1:0] + iAdd : m_uiLambdaMotionSSE[(bIsTransquantBypass && m_costMode==COST_MIXED_LOSSLESS_LOSSY_CODING)?1:0] + iAdd); } +#endif + Void setPredictor( TComMv& rcMv ) + { + m_mvPredictor = rcMv; + } + Void setCostScale( Int iCostScale ) { m_iCostScale = iCostScale; } + __inline Distortion getCost( Int x, Int y ) + { +#if RExt__HIGH_BIT_DEPTH_SUPPORT + return Distortion((m_dCost * getBits(x, y)) / 65536.0); +#else + return m_uiCost * getBits(x, y) >> 16; +#endif + } +#if RExt__HIGH_BIT_DEPTH_SUPPORT + Distortion getCost( UInt b ) { return Distortion(( m_dCost * b ) / 65536.0); } +#else + Distortion getCost( UInt b ) { return ( m_uiCost * b ) >> 16; } +#endif + UInt getBits( Int x, Int y ) + { + return xGetComponentBits((x << m_iCostScale) - m_mvPredictor.getHor()) + + xGetComponentBits((y << m_iCostScale) - m_mvPredictor.getVer()); + } + +private: + + static Distortion xGetSSE ( DistParam* pcDtParam ); + static Distortion xGetSSE4 ( DistParam* pcDtParam ); + static Distortion xGetSSE8 ( DistParam* pcDtParam ); + static Distortion xGetSSE16 ( DistParam* pcDtParam ); + static Distortion xGetSSE32 ( DistParam* pcDtParam ); + static Distortion xGetSSE64 ( DistParam* pcDtParam ); + static Distortion xGetSSE16N ( DistParam* pcDtParam ); + + static Distortion xGetSAD ( DistParam* pcDtParam ); + static Distortion xGetSAD4 ( DistParam* pcDtParam ); + static Distortion xGetSAD8 ( DistParam* pcDtParam ); + static Distortion xGetSAD16 ( DistParam* pcDtParam ); + static Distortion xGetSAD32 ( DistParam* pcDtParam ); + static Distortion xGetSAD64 ( DistParam* pcDtParam ); + static Distortion xGetSAD16N ( DistParam* pcDtParam ); + +#if AMP_SAD + static Distortion xGetSAD12 ( DistParam* pcDtParam ); + static Distortion xGetSAD24 ( DistParam* pcDtParam ); + static Distortion xGetSAD48 ( DistParam* pcDtParam ); + +#endif + + static Distortion xGetHADs ( DistParam* pcDtParam ); + static Distortion xCalcHADs2x2 ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); + static Distortion xCalcHADs4x4 ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); + static Distortion xCalcHADs8x8 ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); + + +public: + + Distortion getDistPart(Int bitDepth, Pel* piCur, Int iCurStride, Pel* piOrg, Int iOrgStride, UInt uiBlkWidth, UInt uiBlkHeight, const ComponentID compID, DFunc eDFunc = DF_SSE ); + +};// END CLASS DEFINITION TComRdCost + +//! \} + +#endif // __TCOMRDCOST__ diff --git a/jctvc/TLibCommon/TComRdCostWeightPrediction.cpp b/jctvc/TLibCommon/TComRdCostWeightPrediction.cpp new file mode 100644 index 0000000..419f749 --- /dev/null +++ b/jctvc/TLibCommon/TComRdCostWeightPrediction.cpp @@ -0,0 +1,489 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRdCostWeightPrediction.cpp + \brief RD cost computation class with Weighted-Prediction +*/ + +#include +#include +#include "TComRdCost.h" +#include "TComRdCostWeightPrediction.h" + +static Distortion xCalcHADs2x2w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); +static Distortion xCalcHADs4x4w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); +static Distortion xCalcHADs8x8w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep ); + + +// -------------------------------------------------------------------------------------------------------------------- +// SAD +// -------------------------------------------------------------------------------------------------------------------- +/** get weighted SAD cost + * \param pcDtParam + * \returns Distortion + */ +Distortion TComRdCostWeightPrediction::xGetSADw( DistParam* pcDtParam ) +{ + const Pel *piOrg = pcDtParam->pOrg; + const Pel *piCur = pcDtParam->pCur; + const Int iCols = pcDtParam->iCols; + const Int iStrideCur = pcDtParam->iStrideCur; + const Int iStrideOrg = pcDtParam->iStrideOrg; + const ComponentID compID = pcDtParam->compIdx; + + assert(compIDwpCur[compID]; + + const Int w0 = wpCur.w; + const Int offset = wpCur.offset; + const Int shift = wpCur.shift; + const Int round = wpCur.round; + + Distortion uiSum = 0; + + for(Int iRows = pcDtParam->iRows; iRows != 0; iRows-- ) + { + for (Int n = 0; n < iCols; n++ ) + { + const Pel pred = ( (w0*piCur[n] + round) >> shift ) + offset ; + + uiSum += abs( piOrg[n] - pred ); + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + pcDtParam->compIdx = MAX_NUM_COMPONENT; // reset for DEBUG (assert test) + + return uiSum >> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8); +} + + +// -------------------------------------------------------------------------------------------------------------------- +// SSE +// -------------------------------------------------------------------------------------------------------------------- +/** get weighted SSD cost + * \param pcDtParam + * \returns Distortion + */ +Distortion TComRdCostWeightPrediction::xGetSSEw( DistParam* pcDtParam ) +{ + const Pel *piOrg = pcDtParam->pOrg; + const Pel *piCur = pcDtParam->pCur; + const Int iCols = pcDtParam->iCols; + const Int iStrideOrg = pcDtParam->iStrideOrg; + const Int iStrideCur = pcDtParam->iStrideCur; + const ComponentID compIdx = pcDtParam->compIdx; + + assert( pcDtParam->iSubShift == 0 ); // NOTE: what is this protecting? + + assert(compIdxwpCur[compIdx]; + const Int w0 = wpCur.w; + const Int offset = wpCur.offset; + const Int shift = wpCur.shift; + const Int round = wpCur.round; + const UInt distortionShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1); + + Distortion sum = 0; + + for(Int iRows = pcDtParam->iRows ; iRows != 0; iRows-- ) + { + for (Int n = 0; n < iCols; n++ ) + { + const Pel pred = ( (w0*piCur[n] + round) >> shift ) + offset ; + const Pel residual = piOrg[n] - pred; + sum += ( Distortion(residual) * Distortion(residual) ) >> distortionShift; + } + piOrg += iStrideOrg; + piCur += iStrideCur; + } + + pcDtParam->compIdx = MAX_NUM_COMPONENT; // reset for DEBUG (assert test) + + return sum; +} + + +// -------------------------------------------------------------------------------------------------------------------- +// HADAMARD with step (used in fractional search) +// -------------------------------------------------------------------------------------------------------------------- +/** get weighted Hadamard cost for 2x2 block + * \param *piOrg + * \param *piCur + * \param iStrideOrg + * \param iStrideCur + * \param iStep + * \returns Distortion + */ +Distortion xCalcHADs2x2w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + const Int round = wpCur.round; + const Int shift = wpCur.shift; + const Int offset = wpCur.offset; + const Int w0 = wpCur.w; + + Distortion satd = 0; + TCoeff diff[4]; + TCoeff m[4]; + + Pel pred; + + pred = ( (w0*piCur[0*iStep ] + round) >> shift ) + offset ; + diff[0] = piOrg[0 ] - pred; + pred = ( (w0*piCur[1*iStep ] + round) >> shift ) + offset ; + diff[1] = piOrg[1 ] - pred; + pred = ( (w0*piCur[0*iStep + iStrideCur] + round) >> shift ) + offset ; + diff[2] = piOrg[iStrideOrg ] - pred; + pred = ( (w0*piCur[1*iStep + iStrideCur] + round) >> shift ) + offset ; + diff[3] = piOrg[iStrideOrg + 1] - pred; + + m[0] = diff[0] + diff[2]; + m[1] = diff[1] + diff[3]; + m[2] = diff[0] - diff[2]; + m[3] = diff[1] - diff[3]; + + satd += abs(m[0] + m[1]); + satd += abs(m[0] - m[1]); + satd += abs(m[2] + m[3]); + satd += abs(m[2] - m[3]); + + return satd; +} + + +/** get weighted Hadamard cost for 4x4 block + * \param *piOrg + * \param *piCur + * \param iStrideOrg + * \param iStrideCur + * \param iStep + * \returns Distortion + */ +Distortion xCalcHADs4x4w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + const Int round = wpCur.round; + const Int shift = wpCur.shift; + const Int offset = wpCur.offset; + const Int w0 = wpCur.w; + + Distortion satd = 0; + TCoeff diff[16]; + TCoeff m[16]; + TCoeff d[16]; + + + for(Int k = 0; k < 16; k+=4 ) + { + Pel pred; + pred = ( (w0*piCur[0*iStep] + round) >> shift ) + offset ; + diff[k+0] = piOrg[0] - pred; + pred = ( (w0*piCur[1*iStep] + round) >> shift ) + offset ; + diff[k+1] = piOrg[1] - pred; + pred = ( (w0*piCur[2*iStep] + round) >> shift ) + offset ; + diff[k+2] = piOrg[2] - pred; + pred = ( (w0*piCur[3*iStep] + round) >> shift ) + offset ; + diff[k+3] = piOrg[3] - pred; + + piCur += iStrideCur; + piOrg += iStrideOrg; + } + + /*===== 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]; + + for (Int k=0; k<16; ++k) + { + satd += abs(d[k]); + } + satd = ((satd+1)>>1); + + return satd; +} + + +/** get weighted Hadamard cost for 8x8 block + * \param *piOrg + * \param *piCur + * \param iStrideOrg + * \param iStrideCur + * \param iStep + * \returns Distortion + */ +Distortion xCalcHADs8x8w( const WPScalingParam &wpCur, const Pel *piOrg, const Pel *piCur, Int iStrideOrg, Int iStrideCur, Int iStep ) +{ + Distortion sad=0; + TCoeff diff[64], m1[8][8], m2[8][8], m3[8][8]; + Int iStep2 = iStep<<1; + Int iStep3 = iStep2 + iStep; + Int iStep4 = iStep3 + iStep; + Int iStep5 = iStep4 + iStep; + Int iStep6 = iStep5 + iStep; + Int iStep7 = iStep6 + iStep; + const Int round = wpCur.round; + const Int shift = wpCur.shift; + const Int offset = wpCur.offset; + const Int w0 = wpCur.w; + + Pel pred; + + for(Int k = 0; k < 64; k+=8 ) + { + pred = ( (w0*piCur[ 0] + round) >> shift ) + offset ; + diff[k+0] = piOrg[0] - pred; + pred = ( (w0*piCur[iStep ] + round) >> shift ) + offset ; + diff[k+1] = piOrg[1] - pred; + pred = ( (w0*piCur[iStep2] + round) >> shift ) + offset ; + diff[k+2] = piOrg[2] - pred; + pred = ( (w0*piCur[iStep3] + round) >> shift ) + offset ; + diff[k+3] = piOrg[3] - pred; + pred = ( (w0*piCur[iStep4] + round) >> shift ) + offset ; + diff[k+4] = piOrg[4] - pred; + pred = ( (w0*piCur[iStep5] + round) >> shift ) + offset ; + diff[k+5] = piOrg[5] - pred; + pred = ( (w0*piCur[iStep6] + round) >> shift ) + offset ; + diff[k+6] = piOrg[6] - pred; + pred = ( (w0*piCur[iStep7] + round) >> shift ) + offset ; + diff[k+7] = piOrg[7] - pred; + + piCur += iStrideCur; + piOrg += iStrideOrg; + } + + //horizontal + for (Int j=0; j < 8; j++) + { + const Int 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 (Int 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 (Int j=0; j < 8; j++) + { + for (Int i=0; i < 8; i++) + { + sad += (abs(m2[j][i])); + } + } + + sad=((sad+2)>>2); + + return sad; +} + + +/** get weighted Hadamard cost + * \param *pcDtParam + * \returns Distortion + */ +Distortion TComRdCostWeightPrediction::xGetHADsw( DistParam* pcDtParam ) +{ + const Pel *piOrg = pcDtParam->pOrg; + const Pel *piCur = pcDtParam->pCur; + const Int iRows = pcDtParam->iRows; + const Int iCols = pcDtParam->iCols; + const Int iStrideCur = pcDtParam->iStrideCur; + const Int iStrideOrg = pcDtParam->iStrideOrg; + const Int iStep = pcDtParam->iStep; + const ComponentID compIdx = pcDtParam->compIdx; + assert(compIdxwpCur[compIdx]; + + Distortion uiSum = 0; + + if( ( iRows % 8 == 0) && (iCols % 8 == 0) ) + { + const Int iOffsetOrg = iStrideOrg<<3; + const Int iOffsetCur = iStrideCur<<3; + for (Int y=0; y> DISTORTION_PRECISION_ADJUSTMENT(pcDtParam->bitDepth-8); +} diff --git a/jctvc/TLibCommon/TComRdCostWeightPrediction.h b/jctvc/TLibCommon/TComRdCostWeightPrediction.h new file mode 100644 index 0000000..1465c79 --- /dev/null +++ b/jctvc/TLibCommon/TComRdCostWeightPrediction.h @@ -0,0 +1,64 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRdCostWeightPrediction.h + \brief RD cost computation namespace (header) +*/ + +#ifndef __TCOMRDCOSTWEIGHTPREDICTION__ +#define __TCOMRDCOSTWEIGHTPREDICTION__ + + +#include "CommonDef.h" +#include "TComPattern.h" +#include "TComMv.h" +#include "TComRdCost.h" +#include "TComSlice.h" + +class DistParam; +class TComPattern; + +// ==================================================================================================================== +// Namespace definition +// ==================================================================================================================== + +/// RD cost computation namespace, with Weighted Prediction +namespace TComRdCostWeightPrediction +{ + Distortion xGetSSEw ( DistParam* pcDtParam ); + Distortion xGetSADw ( DistParam* pcDtParam ); + Distortion xGetHADsw( DistParam* pcDtParam ); +}// END NAMESPACE DEFINITION TComRdCostWeightPrediction + +#endif // __TCOMRDCOSTWEIGHTPREDICTION__ + diff --git a/jctvc/TLibCommon/TComRectangle.h b/jctvc/TLibCommon/TComRectangle.h new file mode 100644 index 0000000..80df3ac --- /dev/null +++ b/jctvc/TLibCommon/TComRectangle.h @@ -0,0 +1,50 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __TCOMRECTANGLE__ +#define __TCOMRECTANGLE__ + + +struct TComRectangle +{ + UInt width; + UInt height; + UInt x0; + UInt y0; +}; + + + + +#endif diff --git a/jctvc/TLibCommon/TComRom.cpp b/jctvc/TLibCommon/TComRom.cpp new file mode 100644 index 0000000..6c62edd --- /dev/null +++ b/jctvc/TLibCommon/TComRom.cpp @@ -0,0 +1,675 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRom.cpp + \brief global variables & functions +*/ + +#include "TComRom.h" +#include +#include +#include +#include +#include +#include "TComDataCU.h" +#include "Debug.h" +// ==================================================================================================================== +// Initialize / destroy functions +// ==================================================================================================================== + +//! \ingroup TLibCommon +//! \{ + +class ScanGenerator +{ +private: + UInt m_line, m_column; + const UInt m_blockWidth, m_blockHeight; + const UInt m_stride; + const COEFF_SCAN_TYPE m_scanType; + +public: + ScanGenerator(UInt blockWidth, UInt blockHeight, UInt stride, COEFF_SCAN_TYPE scanType) + : m_line(0), m_column(0), m_blockWidth(blockWidth), m_blockHeight(blockHeight), m_stride(stride), m_scanType(scanType) + { } + + UInt GetCurrentX() const { return m_column; } + UInt GetCurrentY() const { return m_line; } + + UInt GetNextIndex(UInt blockOffsetX, UInt blockOffsetY) + { + Int rtn=((m_line + blockOffsetY) * m_stride) + m_column + blockOffsetX; + + //advance line and column to the next position + switch (m_scanType) + { + //------------------------------------------------ + + case SCAN_DIAG: + { + if ((m_column == (m_blockWidth - 1)) || (m_line == 0)) //if we reach the end of a rank, go diagonally down to the next one + { + m_line += m_column + 1; + m_column = 0; + + if (m_line >= m_blockHeight) //if that takes us outside the block, adjust so that we are back on the bottom row + { + m_column += m_line - (m_blockHeight - 1); + m_line = m_blockHeight - 1; + } + } + else + { + m_column++; + m_line--; + } + } + break; + + //------------------------------------------------ + + case SCAN_HOR: + { + if (m_column == (m_blockWidth - 1)) + { + m_line++; + m_column = 0; + } + else m_column++; + } + break; + + //------------------------------------------------ + + case SCAN_VER: + { + if (m_line == (m_blockHeight - 1)) + { + m_column++; + m_line = 0; + } + else m_line++; + } + break; + + //------------------------------------------------ + + default: + { + std::cerr << "ERROR: Unknown scan type \"" << m_scanType << "\"in ScanGenerator::GetNextIndex" << std::endl; + exit(1); + } + break; + } + + return rtn; + } +}; + +// initialize ROM variables +Void initROM() +{ + Int i, c; + + // g_aucConvertToBit[ x ]: log2(x/4), if x=4 -> 0, x=8 -> 1, x=16 -> 2, ... + ::memset( g_aucConvertToBit, -1, sizeof( g_aucConvertToBit ) ); + c=0; + for ( i=4; i<=MAX_CU_SIZE; i*=2 ) + { + g_aucConvertToBit[ i ] = c; + c++; + } + + // initialise scan orders + for(UInt log2BlockHeight = 0; log2BlockHeight < MAX_CU_DEPTH; log2BlockHeight++) + { + for(UInt log2BlockWidth = 0; log2BlockWidth < MAX_CU_DEPTH; log2BlockWidth++) + { + const UInt blockWidth = 1 << log2BlockWidth; + const UInt blockHeight = 1 << log2BlockHeight; + const UInt totalValues = blockWidth * blockHeight; + + //-------------------------------------------------------------------------------------------------- + + //non-grouped scan orders + + for (UInt scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++) + { + const COEFF_SCAN_TYPE scanType = COEFF_SCAN_TYPE(scanTypeIndex); + + g_scanOrder[SCAN_UNGROUPED][scanType][log2BlockWidth][log2BlockHeight] = new UInt[totalValues]; + + ScanGenerator fullBlockScan(blockWidth, blockHeight, blockWidth, scanType); + + for (UInt scanPosition = 0; scanPosition < totalValues; scanPosition++) + { + g_scanOrder[SCAN_UNGROUPED][scanType][log2BlockWidth][log2BlockHeight][scanPosition] = fullBlockScan.GetNextIndex(0, 0); + } + } + + //-------------------------------------------------------------------------------------------------- + + //grouped scan orders + + const UInt groupWidth = 1 << MLS_CG_LOG2_WIDTH; + const UInt groupHeight = 1 << MLS_CG_LOG2_HEIGHT; + const UInt widthInGroups = blockWidth >> MLS_CG_LOG2_WIDTH; + const UInt heightInGroups = blockHeight >> MLS_CG_LOG2_HEIGHT; + + const UInt groupSize = groupWidth * groupHeight; + const UInt totalGroups = widthInGroups * heightInGroups; + + for (UInt scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++) + { + const COEFF_SCAN_TYPE scanType = COEFF_SCAN_TYPE(scanTypeIndex); + + g_scanOrder[SCAN_GROUPED_4x4][scanType][log2BlockWidth][log2BlockHeight] = new UInt[totalValues]; + + ScanGenerator fullBlockScan(widthInGroups, heightInGroups, groupWidth, scanType); + + for (UInt groupIndex = 0; groupIndex < totalGroups; groupIndex++) + { + const UInt groupPositionY = fullBlockScan.GetCurrentY(); + const UInt groupPositionX = fullBlockScan.GetCurrentX(); + const UInt groupOffsetX = groupPositionX * groupWidth; + const UInt groupOffsetY = groupPositionY * groupHeight; + const UInt groupOffsetScan = groupIndex * groupSize; + + ScanGenerator groupScan(groupWidth, groupHeight, blockWidth, scanType); + + for (UInt scanPosition = 0; scanPosition < groupSize; scanPosition++) + { + g_scanOrder[SCAN_GROUPED_4x4][scanType][log2BlockWidth][log2BlockHeight][groupOffsetScan + scanPosition] = groupScan.GetNextIndex(groupOffsetX, groupOffsetY); + } + + fullBlockScan.GetNextIndex(0,0); + } + } + + //-------------------------------------------------------------------------------------------------- + } + } +} + +Void destroyROM() +{ + for(UInt groupTypeIndex = 0; groupTypeIndex < SCAN_NUMBER_OF_GROUP_TYPES; groupTypeIndex++) + { + for (UInt scanOrderIndex = 0; scanOrderIndex < SCAN_NUMBER_OF_TYPES; scanOrderIndex++) + { + for (UInt log2BlockWidth = 0; log2BlockWidth < MAX_CU_DEPTH; log2BlockWidth++) + { + for (UInt log2BlockHeight = 0; log2BlockHeight < MAX_CU_DEPTH; log2BlockHeight++) + { + delete [] g_scanOrder[groupTypeIndex][scanOrderIndex][log2BlockWidth][log2BlockHeight]; + } + } + } + } +} + +// ==================================================================================================================== +// Data structure related table & variable +// ==================================================================================================================== + +UInt g_uiMaxCUWidth = MAX_CU_SIZE; +UInt g_uiMaxCUHeight = MAX_CU_SIZE; +UInt g_uiMaxCUDepth = MAX_CU_DEPTH; +UInt g_uiAddCUDepth = 0; +UInt g_auiZscanToRaster [ MAX_NUM_SPU_W*MAX_NUM_SPU_W ] = { 0, }; +UInt g_auiRasterToZscan [ MAX_NUM_SPU_W*MAX_NUM_SPU_W ] = { 0, }; +UInt g_auiRasterToPelX [ MAX_NUM_SPU_W*MAX_NUM_SPU_W ] = { 0, }; +UInt g_auiRasterToPelY [ MAX_NUM_SPU_W*MAX_NUM_SPU_W ] = { 0, }; + +UInt g_auiPUOffset[NUMBER_OF_PART_SIZES] = { 0, 8, 4, 4, 2, 10, 1, 5}; + +Void initZscanToRaster ( Int iMaxDepth, Int iDepth, UInt uiStartVal, UInt*& rpuiCurrIdx ) +{ + Int iStride = 1 << ( iMaxDepth - 1 ); + + if ( iDepth == iMaxDepth ) + { + rpuiCurrIdx[0] = uiStartVal; + rpuiCurrIdx++; + } + else + { + Int iStep = iStride >> iDepth; + initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal, rpuiCurrIdx ); + initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep, rpuiCurrIdx ); + initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep*iStride, rpuiCurrIdx ); + initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep*iStride+iStep, rpuiCurrIdx ); + } +} + +Void initRasterToZscan ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth ) +{ + UInt uiMinCUWidth = uiMaxCUWidth >> ( uiMaxDepth - 1 ); + UInt uiMinCUHeight = uiMaxCUHeight >> ( uiMaxDepth - 1 ); + + UInt uiNumPartInWidth = (UInt)uiMaxCUWidth / uiMinCUWidth; + UInt uiNumPartInHeight = (UInt)uiMaxCUHeight / uiMinCUHeight; + + for ( UInt i = 0; i < uiNumPartInWidth*uiNumPartInHeight; i++ ) + { + g_auiRasterToZscan[ g_auiZscanToRaster[i] ] = i; + } +} + +Void initRasterToPelXY ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth ) +{ + UInt i; + + UInt* uiTempX = &g_auiRasterToPelX[0]; + UInt* uiTempY = &g_auiRasterToPelY[0]; + + UInt uiMinCUWidth = uiMaxCUWidth >> ( uiMaxDepth - 1 ); + UInt uiMinCUHeight = uiMaxCUHeight >> ( uiMaxDepth - 1 ); + + UInt uiNumPartInWidth = uiMaxCUWidth / uiMinCUWidth; + UInt uiNumPartInHeight = uiMaxCUHeight / uiMinCUHeight; + + uiTempX[0] = 0; uiTempX++; + for ( i = 1; i < uiNumPartInWidth; i++ ) + { + uiTempX[0] = uiTempX[-1] + uiMinCUWidth; uiTempX++; + } + for ( i = 1; i < uiNumPartInHeight; i++ ) + { + memcpy(uiTempX, uiTempX-uiNumPartInWidth, sizeof(UInt)*uiNumPartInWidth); + uiTempX += uiNumPartInWidth; + } + + for ( i = 1; i < uiNumPartInWidth*uiNumPartInHeight; i++ ) + { + uiTempY[i] = ( i / uiNumPartInWidth ) * uiMinCUWidth; + } +} + +Int g_maxTrDynamicRange[MAX_NUM_CHANNEL_TYPE]; + +Int g_quantScales[SCALING_LIST_REM_NUM] = +{ + 26214,23302,20560,18396,16384,14564 +}; + +Int g_invQuantScales[SCALING_LIST_REM_NUM] = +{ + 40,45,51,57,64,72 +}; + +//-------------------------------------------------------------------------------------------------- + +//structures + +#define DEFINE_DST4x4_MATRIX(a,b,c,d) \ +{ \ + { a, b, c, d }, \ + { c, c, 0, -c }, \ + { d, -a, -c, b }, \ + { b, -d, c, -a }, \ +} + +#define DEFINE_DCT4x4_MATRIX(a,b,c) \ +{ \ + { a, a, a, a}, \ + { b, c, -c, -b}, \ + { a, -a, -a, a}, \ + { c, -b, b, -c} \ +} + +#define DEFINE_DCT8x8_MATRIX(a,b,c,d,e,f,g) \ +{ \ + { a, a, a, a, a, a, a, a}, \ + { d, e, f, g, -g, -f, -e, -d}, \ + { b, c, -c, -b, -b, -c, c, b}, \ + { e, -g, -d, -f, f, d, g, -e}, \ + { a, -a, -a, a, a, -a, -a, a}, \ + { f, -d, g, e, -e, -g, d, -f}, \ + { c, -b, b, -c, -c, b, -b, c}, \ + { g, -f, e, -d, d, -e, f, -g} \ +} + +#define DEFINE_DCT16x16_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \ +{ \ + { a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a}, \ + { h, i, j, k, l, m, n, o, -o, -n, -m, -l, -k, -j, -i, -h}, \ + { d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d}, \ + { i, l, o, -m, -j, -h, -k, -n, n, k, h, j, m, -o, -l, -i}, \ + { b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b}, \ + { j, o, -k, -i, -n, l, h, m, -m, -h, -l, n, i, k, -o, -j}, \ + { e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e}, \ + { k, -m, -i, o, h, n, -j, -l, l, j, -n, -h, -o, i, m, -k}, \ + { a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a}, \ + { l, -j, -n, h, -o, -i, m, k, -k, -m, i, o, -h, n, j, -l}, \ + { f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f}, \ + { m, -h, l, n, -i, k, o, -j, j, -o, -k, i, -n, -l, h, -m}, \ + { c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c}, \ + { n, -k, h, -j, m, o, -l, i, -i, l, -o, -m, j, -h, k, -n}, \ + { g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g}, \ + { o, -n, m, -l, k, -j, i, -h, h, -i, j, -k, l, -m, n, -o} \ +} + +#define DEFINE_DCT32x32_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E) \ +{ \ + { a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a}, \ + { p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, -E, -D, -C, -B, -A, -z, -y, -x, -w, -v, -u, -t, -s, -r, -q, -p}, \ + { h, i, j, k, l, m, n, o, -o, -n, -m, -l, -k, -j, -i, -h, -h, -i, -j, -k, -l, -m, -n, -o, o, n, m, l, k, j, i, h}, \ + { q, t, w, z, C, -E, -B, -y, -v, -s, -p, -r, -u, -x, -A, -D, D, A, x, u, r, p, s, v, y, B, E, -C, -z, -w, -t, -q}, \ + { d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d, d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d}, \ + { r, w, B, -D, -y, -t, -p, -u, -z, -E, A, v, q, s, x, C, -C, -x, -s, -q, -v, -A, E, z, u, p, t, y, D, -B, -w, -r}, \ + { i, l, o, -m, -j, -h, -k, -n, n, k, h, j, m, -o, -l, -i, -i, -l, -o, m, j, h, k, n, -n, -k, -h, -j, -m, o, l, i}, \ + { s, z, -D, -w, -p, -v, -C, A, t, r, y, -E, -x, -q, -u, -B, B, u, q, x, E, -y, -r, -t, -A, C, v, p, w, D, -z, -s}, \ + { b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b}, \ + { t, C, -y, -p, -x, D, u, s, B, -z, -q, -w, E, v, r, A, -A, -r, -v, -E, w, q, z, -B, -s, -u, -D, x, p, y, -C, -t}, \ + { j, o, -k, -i, -n, l, h, m, -m, -h, -l, n, i, k, -o, -j, -j, -o, k, i, n, -l, -h, -m, m, h, l, -n, -i, -k, o, j}, \ + { u, -E, -t, -v, D, s, w, -C, -r, -x, B, q, y, -A, -p, -z, z, p, A, -y, -q, -B, x, r, C, -w, -s, -D, v, t, E, -u}, \ + { e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e, e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e}, \ + { v, -B, -p, -C, u, w, -A, -q, -D, t, x, -z, -r, -E, s, y, -y, -s, E, r, z, -x, -t, D, q, A, -w, -u, C, p, B, -v}, \ + { k, -m, -i, o, h, n, -j, -l, l, j, -n, -h, -o, i, m, -k, -k, m, i, -o, -h, -n, j, l, -l, -j, n, h, o, -i, -m, k}, \ + { w, -y, -u, A, s, -C, -q, E, p, D, -r, -B, t, z, -v, -x, x, v, -z, -t, B, r, -D, -p, -E, q, C, -s, -A, u, y, -w}, \ + { a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a}, \ + { x, -v, -z, t, B, -r, -D, p, -E, -q, C, s, -A, -u, y, w, -w, -y, u, A, -s, -C, q, E, -p, D, r, -B, -t, z, v, -x}, \ + { l, -j, -n, h, -o, -i, m, k, -k, -m, i, o, -h, n, j, -l, -l, j, n, -h, o, i, -m, -k, k, m, -i, -o, h, -n, -j, l}, \ + { y, -s, -E, r, -z, -x, t, D, -q, A, w, -u, -C, p, -B, -v, v, B, -p, C, u, -w, -A, q, -D, -t, x, z, -r, E, s, -y}, \ + { f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f, f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f}, \ + { z, -p, A, y, -q, B, x, -r, C, w, -s, D, v, -t, E, u, -u, -E, t, -v, -D, s, -w, -C, r, -x, -B, q, -y, -A, p, -z}, \ + { m, -h, l, n, -i, k, o, -j, j, -o, -k, i, -n, -l, h, -m, -m, h, -l, -n, i, -k, -o, j, -j, o, k, -i, n, l, -h, m}, \ + { A, -r, v, -E, -w, q, -z, -B, s, -u, D, x, -p, y, C, -t, t, -C, -y, p, -x, -D, u, -s, B, z, -q, w, E, -v, r, -A}, \ + { c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c}, \ + { B, -u, q, -x, E, y, -r, t, -A, -C, v, -p, w, -D, -z, s, -s, z, D, -w, p, -v, C, A, -t, r, -y, -E, x, -q, u, -B}, \ + { n, -k, h, -j, m, o, -l, i, -i, l, -o, -m, j, -h, k, -n, -n, k, -h, j, -m, -o, l, -i, i, -l, o, m, -j, h, -k, n}, \ + { C, -x, s, -q, v, -A, -E, z, -u, p, -t, y, -D, -B, w, -r, r, -w, B, D, -y, t, -p, u, -z, E, A, -v, q, -s, x, -C}, \ + { g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g, g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g}, \ + { D, -A, x, -u, r, -p, s, -v, y, -B, E, C, -z, w, -t, q, -q, t, -w, z, -C, -E, B, -y, v, -s, p, -r, u, -x, A, -D}, \ + { o, -n, m, -l, k, -j, i, -h, h, -i, j, -k, l, -m, n, -o, -o, n, -m, l, -k, j, -i, h, -h, i, -j, k, -l, m, -n, o}, \ + { E, -D, C, -B, A, -z, y, -x, w, -v, u, -t, s, -r, q, -p, p, -q, r, -s, t, -u, v, -w, x, -y, z, -A, B, -C, D, -E} \ +} + +//-------------------------------------------------------------------------------------------------- + +//coefficients + +#if RExt__HIGH_PRECISION_FORWARD_TRANSFORM +const TMatrixCoeff g_aiT4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4] = +{ + DEFINE_DCT4x4_MATRIX (16384, 21266, 9224), + DEFINE_DCT4x4_MATRIX ( 64, 83, 36) +}; + +const TMatrixCoeff g_aiT8 [TRANSFORM_NUMBER_OF_DIRECTIONS][8][8] = +{ + DEFINE_DCT8x8_MATRIX (16384, 21266, 9224, 22813, 19244, 12769, 4563), + DEFINE_DCT8x8_MATRIX ( 64, 83, 36, 89, 75, 50, 18) +}; + +const TMatrixCoeff g_aiT16[TRANSFORM_NUMBER_OF_DIRECTIONS][16][16] = +{ + DEFINE_DCT16x16_MATRIX(16384, 21266, 9224, 22813, 19244, 12769, 4563, 23120, 22063, 20450, 17972, 14642, 11109, 6446, 2316), + DEFINE_DCT16x16_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9) +}; + +const TMatrixCoeff g_aiT32[TRANSFORM_NUMBER_OF_DIRECTIONS][32][32] = +{ + DEFINE_DCT32x32_MATRIX(16384, 21266, 9224, 22813, 19244, 12769, 4563, 23120, 22063, 20450, 17972, 14642, 11109, 6446, 2316, 23106, 22852, 22445, 21848, 20995, 19810, 18601, 17143, 15718, 13853, 11749, 9846, 7908, 5573, 3281, 946), + DEFINE_DCT32x32_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9, 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4) +}; + +const TMatrixCoeff g_as_DST_MAT_4[TRANSFORM_NUMBER_OF_DIRECTIONS][4][4] = +{ + DEFINE_DST4x4_MATRIX( 7424, 14081, 18893, 21505), + DEFINE_DST4x4_MATRIX( 29, 55, 74, 84) +}; + +#else + +const TMatrixCoeff g_aiT4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4] = +{ + DEFINE_DCT4x4_MATRIX ( 64, 83, 36), + DEFINE_DCT4x4_MATRIX ( 64, 83, 36) +}; + +const TMatrixCoeff g_aiT8 [TRANSFORM_NUMBER_OF_DIRECTIONS][8][8] = +{ + DEFINE_DCT8x8_MATRIX ( 64, 83, 36, 89, 75, 50, 18), + DEFINE_DCT8x8_MATRIX ( 64, 83, 36, 89, 75, 50, 18) +}; + +const TMatrixCoeff g_aiT16[TRANSFORM_NUMBER_OF_DIRECTIONS][16][16] = +{ + DEFINE_DCT16x16_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9), + DEFINE_DCT16x16_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9) +}; + +const TMatrixCoeff g_aiT32[TRANSFORM_NUMBER_OF_DIRECTIONS][32][32] = +{ + DEFINE_DCT32x32_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9, 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4), + DEFINE_DCT32x32_MATRIX( 64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9, 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4) +}; + +const TMatrixCoeff g_as_DST_MAT_4[TRANSFORM_NUMBER_OF_DIRECTIONS][4][4] = +{ + DEFINE_DST4x4_MATRIX( 29, 55, 74, 84), + DEFINE_DST4x4_MATRIX( 29, 55, 74, 84) +}; +#endif + + +//-------------------------------------------------------------------------------------------------- + +#undef DEFINE_DST4x4_MATRIX +#undef DEFINE_DCT4x4_MATRIX +#undef DEFINE_DCT8x8_MATRIX +#undef DEFINE_DCT16x16_MATRIX +#undef DEFINE_DCT32x32_MATRIX + +//-------------------------------------------------------------------------------------------------- + + +const UChar g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSize]= +{ + //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,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 + { 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, 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,33,33,34,34,35,35,36,36,37,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51 }, + { 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,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,51,51,51,51,51,51 }, + { 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,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,51,51,51,51,51,51 } +}; + +// ==================================================================================================================== +// ADI +// ==================================================================================================================== + +#if FAST_UDI_USE_MPM +const UChar g_aucIntraModeNumFast[MAX_CU_DEPTH] = +{ + 3, // 2x2 + 8, // 4x4 + 8, // 8x8 + 3, // 16x16 + 3, // 32x32 + 3 // 64x64 +}; +#else // FAST_UDI_USE_MPM +const UChar g_aucIntraModeNumFast[MAX_CU_DEPTH] = +{ + 3, // 2x2 + 9, // 4x4 + 9, // 8x8 + 4, // 16x16 33 + 4, // 32x32 33 + 5 // 64x64 33 +}; +#endif // FAST_UDI_USE_MPM + +const UChar g_chroma422IntraAngleMappingTable[NUM_INTRA_MODE] = + //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, 30, 31, 32, 33, 34, DM + { 0, 1, 2, 2, 2, 2, 3, 5, 7, 8, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 29, 30, 31, DM_CHROMA_IDX}; + +// ==================================================================================================================== +// Bit-depth +// ==================================================================================================================== + +Int g_bitDepth [MAX_NUM_CHANNEL_TYPE] = {8, 8}; +#if O0043_BEST_EFFORT_DECODING +Int g_bitDepthInStream [MAX_NUM_CHANNEL_TYPE] = {8, 8}; // In the encoder, this is the same as g_bitDepth. In the decoder, this can vary from g_bitDepth if the decoder is forced to use 'best-effort decoding' at a particular bit-depth. +#endif +Int g_PCMBitDepth[MAX_NUM_CHANNEL_TYPE] = {8, 8}; // PCM bit-depth + +// ==================================================================================================================== +// Misc. +// ==================================================================================================================== + +Char g_aucConvertToBit [ MAX_CU_SIZE+1 ]; + +#if ENC_DEC_TRACE +FILE* g_hTrace = NULL; // Set to NULL to open up a file. Set to stdout to use the current output +const Bool g_bEncDecTraceEnable = true; +const Bool g_bEncDecTraceDisable = false; +Bool g_HLSTraceEnable = true; +Bool g_bJustDoIt = false; +UInt64 g_nSymbolCounter = 0; +#endif +// ==================================================================================================================== +// Scanning order & context model mapping +// ==================================================================================================================== + +// scanning order table +UInt* g_scanOrder[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][ MAX_CU_DEPTH ][ MAX_CU_DEPTH ]; + +const UInt ctxIndMap4x4[4*4] = +{ + 0, 1, 4, 5, + 2, 3, 4, 5, + 6, 6, 8, 8, + 7, 7, 8, 8 +}; + +const UInt g_uiMinInGroup[ LAST_SIGNIFICANT_GROUPS ] = {0,1,2,3,4,6,8,12,16,24}; +const UInt g_uiGroupIdx[ MAX_TU_SIZE ] = {0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9}; + +const Char *MatrixType[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM] = +{ + { + "INTRA4X4_LUMA", + "INTRA4X4_CHROMAU", + "INTRA4X4_CHROMAV", + "INTER4X4_LUMA", + "INTER4X4_CHROMAU", + "INTER4X4_CHROMAV" + }, + { + "INTRA8X8_LUMA", + "INTRA8X8_CHROMAU", + "INTRA8X8_CHROMAV", + "INTER8X8_LUMA", + "INTER8X8_CHROMAU", + "INTER8X8_CHROMAV" + }, + { + "INTRA16X16_LUMA", + "INTRA16X16_CHROMAU", + "INTRA16X16_CHROMAV", + "INTER16X16_LUMA", + "INTER16X16_CHROMAU", + "INTER16X16_CHROMAV" + }, + { + "INTRA32X32_LUMA", + "INTRA32X32_CHROMAU_FROM16x16_CHROMAU", + "INTRA32X32_CHROMAV_FROM16x16_CHROMAV", + "INTER32X32_LUMA", + "INTER32X32_CHROMAU_FROM16x16_CHROMAU", + "INTER32X32_CHROMAV_FROM16x16_CHROMAV" + }, +}; + +const Char *MatrixType_DC[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM] = +{ + { + }, + { + }, + { + "INTRA16X16_LUMA_DC", + "INTRA16X16_CHROMAU_DC", + "INTRA16X16_CHROMAV_DC", + "INTER16X16_LUMA_DC", + "INTER16X16_CHROMAU_DC", + "INTER16X16_CHROMAV_DC" + }, + { + "INTRA32X32_LUMA_DC", + "INTRA32X32_CHROMAU_DC_FROM16x16_CHROMAU", + "INTRA32X32_CHROMAV_DC_FROM16x16_CHROMAV", + "INTER32X32_LUMA_DC", + "INTER32X32_CHROMAU_DC_FROM16x16_CHROMAU", + "INTER32X32_CHROMAV_DC_FROM16x16_CHROMAV" + }, +}; + +Int g_quantTSDefault4x4[4*4] = +{ + 16,16,16,16, + 16,16,16,16, + 16,16,16,16, + 16,16,16,16 +}; + +Int g_quantIntraDefault8x8[8*8] = +{ + 16,16,16,16,17,18,21,24, + 16,16,16,16,17,19,22,25, + 16,16,17,18,20,22,25,29, + 16,16,18,21,24,27,31,36, + 17,17,20,24,30,35,41,47, + 18,19,22,27,35,44,54,65, + 21,22,25,31,41,54,70,88, + 24,25,29,36,47,65,88,115 +}; + +Int g_quantInterDefault8x8[8*8] = +{ + 16,16,16,16,17,18,20,24, + 16,16,16,17,18,20,24,25, + 16,16,17,18,20,24,25,28, + 16,17,18,20,24,25,28,33, + 17,18,20,24,25,28,33,41, + 18,20,24,25,28,33,41,54, + 20,24,25,28,33,41,54,71, + 24,25,28,33,41,54,71,91 +}; + +UInt g_scalingListSize [SCALING_LIST_SIZE_NUM] = {16,64,256,1024}; +UInt g_scalingListSizeX [SCALING_LIST_SIZE_NUM] = { 4, 8, 16, 32}; + +//! \} diff --git a/jctvc/TLibCommon/TComRom.h b/jctvc/TLibCommon/TComRom.h new file mode 100644 index 0000000..e57727c --- /dev/null +++ b/jctvc/TLibCommon/TComRom.h @@ -0,0 +1,237 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComRom.h + \brief global variables & functions (header) +*/ + +#ifndef __TCOMROM__ +#define __TCOMROM__ + +#include "CommonDef.h" + +#include +#include + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Macros +// ==================================================================================================================== + +#define MAX_CU_DEPTH 6 // log2(CTUSize) +#define MAX_CU_SIZE (1<<(MAX_CU_DEPTH)) // maximum allowable size of CU, surely 64? (not 1<<7 = 128) +#define MIN_PU_SIZE 4 +#define MIN_TU_SIZE 4 +#define MAX_TU_SIZE 32 +#define MAX_NUM_SPU_W (MAX_CU_SIZE/MIN_PU_SIZE) // maximum number of SPU in horizontal line + +#define SCALING_LIST_REM_NUM 6 + +// ==================================================================================================================== +// Initialize / destroy functions +// ==================================================================================================================== + +Void initROM(); +Void destroyROM(); + +// ==================================================================================================================== +// Data structure related table & variable +// ==================================================================================================================== + +// flexible conversion from relative to absolute index +extern UInt g_auiZscanToRaster[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ]; +extern UInt g_auiRasterToZscan[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ]; +extern UInt* g_scanOrder[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][ MAX_CU_DEPTH ][ MAX_CU_DEPTH ]; + +Void initZscanToRaster ( Int iMaxDepth, Int iDepth, UInt uiStartVal, UInt*& rpuiCurrIdx ); +Void initRasterToZscan ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth ); + +// conversion of partition index to picture pel position +extern UInt g_auiRasterToPelX[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ]; +extern UInt g_auiRasterToPelY[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ]; + +Void initRasterToPelXY ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth ); + +// global variable (CTU width/height, max. CU depth) +extern UInt g_uiMaxCUWidth; +extern UInt g_uiMaxCUHeight; +extern UInt g_uiMaxCUDepth; +extern UInt g_uiAddCUDepth; + +extern UInt g_auiPUOffset[NUMBER_OF_PART_SIZES]; + +#define QUANT_SHIFT 14 // Q(4) = 2^14 +#define IQUANT_SHIFT 6 +#define SCALE_BITS 15 // Inherited from TMuC, pressumably for fractional bit estimates in RDOQ + +extern Int g_maxTrDynamicRange[MAX_NUM_CHANNEL_TYPE]; + +#define SQRT2 11585 +#define SQRT2_SHIFT 13 +#define INVSQRT2 11585 +#define INVSQRT2_SHIFT 14 +#define ADDITIONAL_MULTIPLIER_BITS 14 + +#define SHIFT_INV_1ST 7 // Shift after first inverse transform stage +#define SHIFT_INV_2ND 12 // Shift after second inverse transform stage + +extern Int g_quantScales[SCALING_LIST_REM_NUM]; // Q(QP%6) +extern Int g_invQuantScales[SCALING_LIST_REM_NUM]; // IQ(QP%6) + +#if RExt__HIGH_PRECISION_FORWARD_TRANSFORM +static const Int g_transformMatrixShift[TRANSFORM_NUMBER_OF_DIRECTIONS] = { 14, 6 }; +#else +static const Int g_transformMatrixShift[TRANSFORM_NUMBER_OF_DIRECTIONS] = { 6, 6 }; +#endif + +extern const TMatrixCoeff g_aiT4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4]; +extern const TMatrixCoeff g_aiT8 [TRANSFORM_NUMBER_OF_DIRECTIONS][8][8]; +extern const TMatrixCoeff g_aiT16[TRANSFORM_NUMBER_OF_DIRECTIONS][16][16]; +extern const TMatrixCoeff g_aiT32[TRANSFORM_NUMBER_OF_DIRECTIONS][32][32]; + +// ==================================================================================================================== +// Luma QP to Chroma QP mapping +// ==================================================================================================================== + +static const Int chromaQPMappingTableSize = 58; + +extern const UChar g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSize]; + +// ==================================================================================================================== +// Entropy Coding +// ==================================================================================================================== + +#define CONTEXT_STATE_BITS 6 +#define LAST_SIGNIFICANT_GROUPS 10 + +// ==================================================================================================================== +// Scanning order & context mapping table +// ==================================================================================================================== + +extern const UInt ctxIndMap4x4[4*4]; + +extern const UInt g_uiGroupIdx[ MAX_TU_SIZE ]; +extern const UInt g_uiMinInGroup[ LAST_SIGNIFICANT_GROUPS ]; + +// ==================================================================================================================== +// ADI table +// ==================================================================================================================== + +extern const UChar g_aucIntraModeNumFast[MAX_CU_DEPTH]; + +extern const UChar g_chroma422IntraAngleMappingTable[NUM_INTRA_MODE]; + +// ==================================================================================================================== +// Bit-depth +// ==================================================================================================================== + +extern Int g_bitDepth [MAX_NUM_CHANNEL_TYPE]; +extern Int g_PCMBitDepth[MAX_NUM_CHANNEL_TYPE]; +#if O0043_BEST_EFFORT_DECODING +extern Int g_bitDepthInStream [MAX_NUM_CHANNEL_TYPE]; // In the encoder, this is the same as g_bitDepth. In the decoder, this can vary from g_bitDepth if the decoder is forced to use 'best-effort decoding' at a particular bit-depth. +#endif + +// ==================================================================================================================== +// Mode-Dependent DST Matrices +// ==================================================================================================================== + +extern const TMatrixCoeff g_as_DST_MAT_4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4]; + +// ==================================================================================================================== +// Misc. +// ==================================================================================================================== + +extern Char g_aucConvertToBit [ MAX_CU_SIZE+1 ]; // from width to log2(width)-2 + +#ifndef ENC_DEC_TRACE +#define ENC_DEC_TRACE 0 +#endif + + +#if ENC_DEC_TRACE +extern FILE* g_hTrace; +extern Bool g_bJustDoIt; +extern const Bool g_bEncDecTraceEnable; +extern const Bool g_bEncDecTraceDisable; +extern Bool g_HLSTraceEnable; +extern UInt64 g_nSymbolCounter; + +#define COUNTER_START 1 +#define COUNTER_END 0 //( UInt64(1) << 63 ) + +#define DTRACE_CABAC_F(x) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "%f", x ); +#define DTRACE_CABAC_V(x) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "%d", x ); +#define DTRACE_CABAC_VL(x) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "%lld", x ); +#define DTRACE_CABAC_T(x) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "%s", x ); +#define DTRACE_CABAC_X(x) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "%x", x ); +#define DTRACE_CABAC_R( x,y ) if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, x, y ); +#define DTRACE_CABAC_N if ( ( g_nSymbolCounter >= COUNTER_START && g_nSymbolCounter <= COUNTER_END )|| g_bJustDoIt ) fprintf( g_hTrace, "\n" ); + +#else + +#define DTRACE_CABAC_F(x) +#define DTRACE_CABAC_V(x) +#define DTRACE_CABAC_VL(x) +#define DTRACE_CABAC_T(x) +#define DTRACE_CABAC_X(x) +#define DTRACE_CABAC_R( x,y ) +#define DTRACE_CABAC_N + +#endif + + +#define SCALING_LIST_NUM (MAX_NUM_COMPONENT * NUMBER_OF_PREDICTION_MODES) ///< list number for quantization matrix + +#define SCALING_LIST_START_VALUE 8 ///< start value for dpcm mode +#define MAX_MATRIX_COEF_NUM 64 ///< max coefficient number for quantization matrix +#define MAX_MATRIX_SIZE_NUM 8 ///< max size number for quantization matrix +#define SCALING_LIST_BITS 8 ///< bit depth of scaling list entries +#define LOG2_SCALING_LIST_NEUTRAL_VALUE 4 ///< log2 of the value that, when used in a scaling list, has no effect on quantisation +#define SCALING_LIST_DC 16 ///< default DC value + +extern const Char *MatrixType[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; +extern const Char *MatrixType_DC[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; + +extern Int g_quantTSDefault4x4[4*4]; +extern Int g_quantIntraDefault8x8[8*8]; +extern Int g_quantInterDefault8x8[8*8]; + +extern UInt g_scalingListSize [SCALING_LIST_SIZE_NUM]; +extern UInt g_scalingListSizeX[SCALING_LIST_SIZE_NUM]; +extern UInt g_scalingListNum [SCALING_LIST_SIZE_NUM]; +//! \} + +#endif //__TCOMROM__ + diff --git a/jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp b/jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp new file mode 100644 index 0000000..e2d37d3 --- /dev/null +++ b/jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp @@ -0,0 +1,724 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComSampleAdaptiveOffset.cpp + \brief sample adaptive offset class +*/ + +#include "TComSampleAdaptiveOffset.h" +#include +#include +#include +#include + +//! \ingroup TLibCommon +//! \{ + +UInt g_saoMaxOffsetQVal[MAX_NUM_COMPONENT]; + +SAOOffset::SAOOffset() +{ + reset(); +} + +SAOOffset::~SAOOffset() +{ + +} + +Void SAOOffset::reset() +{ + modeIdc = SAO_MODE_OFF; + typeIdc = -1; + typeAuxInfo = -1; + ::memset(offset, 0, sizeof(Int)* MAX_NUM_SAO_CLASSES); +} + +const SAOOffset& SAOOffset::operator= (const SAOOffset& src) +{ + modeIdc = src.modeIdc; + typeIdc = src.typeIdc; + typeAuxInfo = src.typeAuxInfo; + ::memcpy(offset, src.offset, sizeof(Int)* MAX_NUM_SAO_CLASSES); + + return *this; +} + + +SAOBlkParam::SAOBlkParam() +{ + reset(); +} + +SAOBlkParam::~SAOBlkParam() +{ + +} + +Void SAOBlkParam::reset() +{ + for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + offsetParam[compIdx].reset(); + } +} + +const SAOBlkParam& SAOBlkParam::operator= (const SAOBlkParam& src) +{ + for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + offsetParam[compIdx] = src.offsetParam[compIdx]; + } + return *this; + +} + +TComSampleAdaptiveOffset::TComSampleAdaptiveOffset() +{ + m_tempPicYuv = NULL; + m_lineBufWidth = 0; + m_signLineBuf1 = NULL; + m_signLineBuf2 = NULL; +} + + +TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset() +{ + destroy(); + + if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL; + if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL; +} + +Void TComSampleAdaptiveOffset::create( Int picWidth, Int picHeight, ChromaFormat format, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth, UInt lumaBitShift, UInt chromaBitShift ) +{ + destroy(); + + m_picWidth = picWidth; + m_picHeight = picHeight; + m_chromaFormatIDC = format; + m_maxCUWidth = maxCUWidth; + m_maxCUHeight = maxCUHeight; + + m_numCTUInWidth = (m_picWidth/m_maxCUWidth) + ((m_picWidth % m_maxCUWidth)?1:0); + m_numCTUInHeight = (m_picHeight/m_maxCUHeight) + ((m_picHeight % m_maxCUHeight)?1:0); + m_numCTUsPic = m_numCTUInHeight*m_numCTUInWidth; + + //temporary picture buffer + if ( !m_tempPicYuv ) + { + m_tempPicYuv = new TComPicYuv; + m_tempPicYuv->create( m_picWidth, m_picHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, maxCUDepth ); + } + + //bit-depth related + for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + Int bitDepthSample = g_bitDepth[toChannelType(ComponentID(compIdx))]; + m_offsetStepLog2 [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift; + g_saoMaxOffsetQVal[compIdx] = (1<<(min(bitDepthSample,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; //Table 9-32, inclusive + } +} + +Void TComSampleAdaptiveOffset::destroy() +{ + if ( m_tempPicYuv ) + { + m_tempPicYuv->destroy(); + delete m_tempPicYuv; + m_tempPicYuv = NULL; + } +} + +Void TComSampleAdaptiveOffset::invertQuantOffsets(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets) +{ + Int codedOffset[MAX_NUM_SAO_CLASSES]; + + ::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES); + ::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES); + + if(typeIdc == SAO_TYPE_START_BO) + { + for(Int i=0; i< 4; i++) + { + dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1< 0) + { + mergedCTUPos = ctuRsAddr- m_numCTUInWidth; + if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) ) + { + mergeCandidate = &(blkParams[mergedCTUPos]); + } + } + } + break; + case SAO_MERGE_LEFT: + { + if(ctuX > 0) + { + mergedCTUPos = ctuRsAddr- 1; + if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) ) + { + mergeCandidate = &(blkParams[mergedCTUPos]); + } + } + } + break; + default: + { + printf("not a supported merge type"); + assert(0); + exit(-1); + } + } + + mergeList[mergeType]=mergeCandidate; + if (mergeCandidate != NULL) + { + numValidMergeCandidates++; + } + } + + return numValidMergeCandidates; +} + + +Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES]) +{ + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + const ComponentID component = ComponentID(compIdx); + SAOOffset& offsetParam = recParam[component]; + + if(offsetParam.modeIdc == SAO_MODE_OFF) + { + continue; + } + + switch(offsetParam.modeIdc) + { + case SAO_MODE_NEW: + { + invertQuantOffsets(component, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset); + } + break; + case SAO_MODE_MERGE: + { + SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc]; + assert(mergeTarget != NULL); + + offsetParam = (*mergeTarget)[component]; + } + break; + default: + { + printf("Not a supported mode"); + assert(0); + exit(-1); + } + } + } +} + +Void TComSampleAdaptiveOffset::reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams) +{ + for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + m_picSAOEnabled[compIdx] = false; + } + + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + + for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++) + { + SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL }; + getMergeList(pic, ctuRsAddr, saoBlkParams, mergeList); + + reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList); + + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF) + { + m_picSAOEnabled[compIdx] = true; + } + } + } +} + + +Void TComSampleAdaptiveOffset::offsetBlock(ComponentID compIdx, Int typeIdx, Int* offset + , Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride, Int width, Int height + , Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail) +{ + if(m_lineBufWidth != m_maxCUWidth) + { + m_lineBufWidth = m_maxCUWidth; + + if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL; + m_signLineBuf1 = new Char[m_lineBufWidth+1]; + + if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL; + m_signLineBuf2 = new Char[m_lineBufWidth+1]; + } + + const Int maxSampleValueIncl = (1<< g_bitDepth[toChannelType(compIdx)] )-1; + + Int x,y, startX, startY, endX, endY, edgeType; + Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX; + Char signLeft, signRight, signDown; + + Pel* srcLine = srcBlk; + Pel* resLine = resBlk; + + switch(typeIdx) + { + case SAO_TYPE_EO_0: + { + offset += 2; + startX = isLeftAvail ? 0 : 1; + endX = isRightAvail ? width : (width -1); + for (y=0; y< height; y++) + { + signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]); + for (x=startX; x< endX; x++) + { + signRight = (Char)sgn(srcLine[x] - srcLine[x+1]); + edgeType = signRight + signLeft; + signLeft = -signRight; + + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + } + srcLine += srcStride; + resLine += resStride; + } + + } + break; + case SAO_TYPE_EO_90: + { + offset += 2; + Char *signUpLine = m_signLineBuf1; + + startY = isAboveAvail ? 0 : 1; + endY = isBelowAvail ? height : height-1; + if (!isAboveAvail) + { + srcLine += srcStride; + resLine += resStride; + } + + Pel* srcLineAbove= srcLine- srcStride; + for (x=0; x< width; x++) + { + signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]); + } + + Pel* srcLineBelow; + for (y=startY; y(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + } + srcLine += srcStride; + resLine += resStride; + } + + } + break; + case SAO_TYPE_EO_135: + { + offset += 2; + Char *signUpLine, *signDownLine, *signTmpLine; + + signUpLine = m_signLineBuf1; + signDownLine= m_signLineBuf2; + + startX = isLeftAvail ? 0 : 1 ; + endX = isRightAvail ? width : (width-1); + + //prepare 2nd line's upper sign + Pel* srcLineBelow= srcLine+ srcStride; + for (x=startX; x< endX+1; x++) + { + signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x- 1]); + } + + //1st line + Pel* srcLineAbove= srcLine- srcStride; + firstLineStartX = isAboveLeftAvail ? 0 : 1; + firstLineEndX = isAboveAvail? endX: 1; + for(x= firstLineStartX; x< firstLineEndX; x++) + { + edgeType = sgn(srcLine[x] - srcLineAbove[x- 1]) - signUpLine[x+1]; + + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + } + srcLine += srcStride; + resLine += resStride; + + + //middle lines + for (y= 1; y< height-1; y++) + { + srcLineBelow= srcLine+ srcStride; + + for (x=startX; x(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + + signDownLine[x+1] = -signDown; + } + signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]); + + signTmpLine = signUpLine; + signUpLine = signDownLine; + signDownLine = signTmpLine; + + srcLine += srcStride; + resLine += resStride; + } + + //last line + srcLineBelow= srcLine+ srcStride; + lastLineStartX = isBelowAvail ? startX : (width -1); + lastLineEndX = isBelowRightAvail ? width : (width -1); + for(x= lastLineStartX; x< lastLineEndX; x++) + { + edgeType = sgn(srcLine[x] - srcLineBelow[x+ 1]) + signUpLine[x]; + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + + } + } + break; + case SAO_TYPE_EO_45: + { + offset += 2; + Char *signUpLine = m_signLineBuf1+1; + + startX = isLeftAvail ? 0 : 1; + endX = isRightAvail ? width : (width -1); + + //prepare 2nd line upper sign + Pel* srcLineBelow= srcLine+ srcStride; + for (x=startX-1; x< endX; x++) + { + signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]); + } + + + //first line + Pel* srcLineAbove= srcLine- srcStride; + firstLineStartX = isAboveAvail ? startX : (width -1 ); + firstLineEndX = isAboveRightAvail ? width : (width-1); + for(x= firstLineStartX; x< firstLineEndX; x++) + { + edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) -signUpLine[x-1]; + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + } + srcLine += srcStride; + resLine += resStride; + + //middle lines + for (y= 1; y< height-1; y++) + { + srcLineBelow= srcLine+ srcStride; + + for(x= startX; x< endX; x++) + { + signDown = (Char)sgn(srcLine[x] - srcLineBelow[x-1]); + edgeType = signDown + signUpLine[x]; + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + signUpLine[x-1] = -signDown; + } + signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]); + srcLine += srcStride; + resLine += resStride; + } + + //last line + srcLineBelow= srcLine+ srcStride; + lastLineStartX = isBelowLeftAvail ? 0 : 1; + lastLineEndX = isBelowAvail ? endX : 1; + for(x= lastLineStartX; x< lastLineEndX; x++) + { + edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + signUpLine[x]; + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]); + + } + } + break; + case SAO_TYPE_BO: + { + const Int shiftBits = g_bitDepth[toChannelType(compIdx)] - NUM_SAO_BO_CLASSES_LOG2; + for (y=0; y< height; y++) + { + for (x=0; x< width; x++) + { + resLine[x] = Clip3(0, maxSampleValueIncl, srcLine[x] + offset[srcLine[x] >> shiftBits] ); + } + srcLine += srcStride; + resLine += resStride; + } + } + break; + default: + { + printf("Not a supported SAO types\n"); + assert(0); + exit(-1); + } + } +} + +Void TComSampleAdaptiveOffset::offsetCTU(Int ctuRsAddr, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic) +{ + Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail; + + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + Bool bAllOff=true; + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF) bAllOff=false; + } + if (bAllOff) return; + + //block boundary availability + pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail); + + Int yPos = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight; + Int xPos = (ctuRsAddr % m_numCTUInWidth)*m_maxCUWidth; + Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight; + Int width = (xPos + m_maxCUWidth > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth; + + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + const ComponentID component = ComponentID(compIdx); + SAOOffset& ctbOffset = saoblkParam[compIdx]; + + if(ctbOffset.modeIdc != SAO_MODE_OFF) + { + const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat()); + const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat()); + + Int blkWidth = (width >> componentScaleX); + Int blkHeight = (height >> componentScaleY); + Int blkXPos = (xPos >> componentScaleX); + Int blkYPos = (yPos >> componentScaleY); + + Int srcStride = srcYuv->getStride(component); + Pel* srcBlk = srcYuv->getAddr(component) + blkYPos*srcStride + blkXPos; + + Int resStride = resYuv->getStride(component); + Pel* resBlk = resYuv->getAddr(component) + blkYPos*resStride + blkXPos; + + offsetBlock( component, ctbOffset.typeIdc, ctbOffset.offset + , srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight + , isLeftAvail, isRightAvail + , isAboveAvail, isBelowAvail + , isAboveLeftAvail, isAboveRightAvail + , isBelowLeftAvail, isBelowRightAvail + ); + } + } //compIdx + +} + + +Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pDecPic) +{ + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + Bool bAllDisabled=true; + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + if (m_picSAOEnabled[compIdx]) bAllDisabled=false; + } + if (bAllDisabled) return; + + TComPicYuv* resYuv = pDecPic->getPicYuvRec(); + TComPicYuv* srcYuv = m_tempPicYuv; + resYuv->copyToPic(srcYuv); + for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++) + { + offsetCTU(ctuRsAddr, srcYuv, resYuv, (pDecPic->getPicSym()->getSAOBlkParam())[ctuRsAddr], pDecPic); + } //ctu +} + + +/** PCM LF disable process. + * \param pcPic picture (TComPic) pointer + * \returns Void + * + * \note Replace filtered sample values of PCM mode blocks with the transmitted and reconstructed ones. + */ +Void TComSampleAdaptiveOffset::PCMLFDisableProcess (TComPic* pcPic) +{ + xPCMRestoration(pcPic); +} + +/** Picture-level PCM restoration. + * \param pcPic picture (TComPic) pointer + * \returns Void + */ +Void TComSampleAdaptiveOffset::xPCMRestoration(TComPic* pcPic) +{ + Bool bPCMFilter = (pcPic->getSlice(0)->getSPS()->getUsePCM() && pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag())? true : false; + + if(bPCMFilter || pcPic->getSlice(0)->getPPS()->getTransquantBypassEnableFlag()) + { + for( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame() ; ctuRsAddr++ ) + { + TComDataCU* pcCU = pcPic->getCtu(ctuRsAddr); + + xPCMCURestoration(pcCU, 0, 0); + } + } +} + +/** PCM CU restoration. + * \param pcCU pointer to current CU + * \param uiAbsPartIdx part index + * \param uiDepth CU depth + * \returns Void + */ +Void TComSampleAdaptiveOffset::xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth ) +{ + TComPic* pcPic = pcCU->getPic(); + UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1); + UInt uiQNumParts = uiCurNumParts>>2; + + // go to sub-CU + if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth ) + { + for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts ) + { + UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ]; + UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ]; + if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) ) + xPCMCURestoration( pcCU, uiAbsZorderIdx, uiDepth+1 ); + } + return; + } + + // restore PCM samples + if ((pcCU->getIPCMFlag(uiAbsZorderIdx)&& pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag()) || pcCU->isLosslessCoded( uiAbsZorderIdx)) + { + const UInt numComponents=pcPic->getNumberValidComponents(); + for(UInt comp=0; compgetPic()->getPicYuvRec(); + UInt uiPcmLeftShiftBit; + const UInt uiMinCoeffSize = pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight(); + const UInt csx=pcPicYuvRec->getComponentScaleX(compID); + const UInt csy=pcPicYuvRec->getComponentScaleY(compID); + const UInt uiOffset = (uiMinCoeffSize*uiAbsZorderIdx)>>(csx+csy); + + Pel *piSrc = pcPicYuvRec->getAddr(compID, pcCU->getCtuRsAddr(), uiAbsZorderIdx); + const Pel *piPcm = pcCU->getPCMSample(compID) + uiOffset; + const UInt uiStride = pcPicYuvRec->getStride(compID); + const UInt uiWidth = ((g_uiMaxCUWidth >> uiDepth) >> csx); + const UInt uiHeight = ((g_uiMaxCUWidth >> uiDepth) >> csy); + + if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) ) + { + uiPcmLeftShiftBit = 0; + } + else + { + uiPcmLeftShiftBit = g_bitDepth[toChannelType(compID)] - pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID)); + } + + for(UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for(UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + piSrc[uiX] = (piPcm[uiX] << uiPcmLeftShiftBit); + } + piPcm += uiWidth; + piSrc += uiStride; + } +} + +//! \} diff --git a/jctvc/TLibCommon/TComSampleAdaptiveOffset.h b/jctvc/TLibCommon/TComSampleAdaptiveOffset.h new file mode 100644 index 0000000..e49559c --- /dev/null +++ b/jctvc/TLibCommon/TComSampleAdaptiveOffset.h @@ -0,0 +1,106 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComSampleAdaptiveOffset.h + \brief sample adaptive offset class (header) +*/ + +#ifndef __TCOMSAMPLEADAPTIVEOFFSET__ +#define __TCOMSAMPLEADAPTIVEOFFSET__ + +#include "CommonDef.h" +#include "TComPic.h" + +//! \ingroup TLibCommon +//! \{ + + +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +#define MAX_SAO_TRUNCATED_BITDEPTH 10 + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== +extern UInt g_saoMaxOffsetQVal[MAX_NUM_COMPONENT]; + +template Int sgn(T val) +{ + return (T(0) < val) - (val < T(0)); +} + +class TComSampleAdaptiveOffset +{ +public: + TComSampleAdaptiveOffset(); + virtual ~TComSampleAdaptiveOffset(); + Void SAOProcess(TComPic* pDecPic); + Void create( Int picWidth, Int picHeight, ChromaFormat format, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth, UInt lumaBitShift, UInt chromaBitShift ); + Void destroy(); + Void reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams); + Void PCMLFDisableProcess (TComPic* pcPic); +protected: + Void offsetBlock(ComponentID compIdx, Int typeIdx, Int* offset, Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride, Int width, Int height + , Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail); + Void invertQuantOffsets(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets); + Void reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES]); + Int getMergeList(TComPic* pic, Int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES]); + Void offsetCTU(Int ctuRsAddr, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic); + Void xPCMRestoration(TComPic* pcPic); + Void xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth ); + Void xPCMSampleRestoration (TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, ComponentID component); +protected: + UInt m_offsetStepLog2[MAX_NUM_COMPONENT]; //offset step + TComPicYuv* m_tempPicYuv; //temporary buffer + Int m_picWidth; + Int m_picHeight; + Int m_maxCUWidth; + Int m_maxCUHeight; + Int m_numCTUInWidth; + Int m_numCTUInHeight; + Int m_numCTUsPic; + + + Int m_lineBufWidth; + Char* m_signLineBuf1; + Char* m_signLineBuf2; + ChromaFormat m_chromaFormatIDC; +private: + Bool m_picSAOEnabled[MAX_NUM_COMPONENT]; +}; + +//! \} +#endif + diff --git a/jctvc/TLibCommon/TComSlice.cpp b/jctvc/TLibCommon/TComSlice.cpp new file mode 100644 index 0000000..89363e4 --- /dev/null +++ b/jctvc/TLibCommon/TComSlice.cpp @@ -0,0 +1,2417 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComSlice.cpp + \brief slice header and SPS class +*/ + +#include "CommonDef.h" +#include "TComSlice.h" +#include "TComPic.h" +#include "TLibEncoder/TEncSbac.h" +//#include "TLibDecoder/TDecSbac.h" + + +//! \ingroup TLibCommon +//! \{ + +TComSlice::TComSlice() +: m_iPPSId ( -1 ) +, m_PicOutputFlag ( true ) +, m_iPOC ( 0 ) +, m_iLastIDR ( 0 ) +, m_iAssociatedIRAP ( 0 ) +, m_iAssociatedIRAPType ( NAL_UNIT_INVALID ) +, m_pcRPS ( 0 ) +, m_LocalRPS ( ) +, m_iBDidx ( 0 ) +, m_RefPicListModification ( ) +, m_eNalUnitType ( NAL_UNIT_CODED_SLICE_IDR_W_RADL ) +, m_eSliceType ( I_SLICE ) +, m_iSliceQp ( 0 ) +, m_dependentSliceSegmentFlag ( false ) +#if ADAPTIVE_QP_SELECTION +, m_iSliceQpBase ( 0 ) +#endif +, m_ChromaQpAdjEnabled ( false ) +, m_deblockingFilterDisable ( false ) +, m_deblockingFilterOverrideFlag ( false ) +, m_deblockingFilterBetaOffsetDiv2( 0 ) +, m_deblockingFilterTcOffsetDiv2 ( 0 ) +, m_bCheckLDC ( false ) +, m_iSliceQpDelta ( 0 ) +, m_iDepth ( 0 ) +, m_bRefenced ( false ) +, m_pcVPS ( NULL ) +, m_pcSPS ( NULL ) +, m_pcPPS ( NULL ) +, m_pcPic ( NULL ) +#if ADAPTIVE_QP_SELECTION +, m_pcTrQuant ( NULL ) +#endif +, m_colFromL0Flag ( 1 ) +, m_noOutputPriorPicsFlag ( false ) +, m_noRaslOutputFlag ( false ) +, m_handleCraAsBlaFlag ( false ) +, m_colRefIdx ( 0 ) +, m_maxNumMergeCand ( 0 ) +, m_uiTLayer ( 0 ) +, m_bTLayerSwitchingFlag ( false ) +, m_sliceMode ( NO_SLICES ) +, m_sliceArgument ( 0 ) +, m_sliceCurStartCtuTsAddr ( 0 ) +, m_sliceCurEndCtuTsAddr ( 0 ) +, m_sliceIdx ( 0 ) +, m_sliceSegmentMode ( NO_SLICES ) +, m_sliceSegmentArgument ( 0 ) +, m_sliceSegmentCurStartCtuTsAddr ( 0 ) +, m_sliceSegmentCurEndCtuTsAddr ( 0 ) +, m_nextSlice ( false ) +, m_nextSliceSegment ( false ) +, m_sliceBits ( 0 ) +, m_sliceSegmentBits ( 0 ) +, m_bFinalized ( false ) +, m_substreamSizes ( ) +, m_scalingList ( NULL ) +, m_cabacInitFlag ( false ) +, m_bLMvdL1Zero ( false ) +, m_temporalLayerNonReferenceFlag ( false ) +, m_LFCrossSliceBoundaryFlag ( false ) +, m_enableTMVPFlag ( true ) +{ + for(UInt i=0; i& rcListPic) +{ + TComPic* pcPicExtract; + TComPic* pcPicInsert; + + TComList::iterator iterPicExtract; + TComList::iterator iterPicExtract_1; + TComList::iterator iterPicInsert; + + for (Int i = 1; i < (Int)(rcListPic.size()); i++) + { + iterPicExtract = rcListPic.begin(); + for (Int j = 0; j < i; j++) iterPicExtract++; + pcPicExtract = *(iterPicExtract); + pcPicExtract->setCurrSliceIdx(0); + + iterPicInsert = rcListPic.begin(); + while (iterPicInsert != iterPicExtract) + { + pcPicInsert = *(iterPicInsert); + pcPicInsert->setCurrSliceIdx(0); + if (pcPicInsert->getPOC() >= pcPicExtract->getPOC()) + { + break; + } + + iterPicInsert++; + } + + iterPicExtract_1 = iterPicExtract; iterPicExtract_1++; + + // swap iterPicExtract and iterPicInsert, iterPicExtract = curr. / iterPicInsert = insertion position + rcListPic.insert (iterPicInsert, iterPicExtract, iterPicExtract_1); + rcListPic.erase (iterPicExtract); + } +} + +TComPic* TComSlice::xGetRefPic (TComList& rcListPic, Int poc) +{ + TComList::iterator iterPic = rcListPic.begin(); + TComPic* pcPic = *(iterPic); + while ( iterPic != rcListPic.end() ) + { + if(pcPic->getPOC() == poc) + { + break; + } + iterPic++; + pcPic = *(iterPic); + } + return pcPic; +} + + +TComPic* TComSlice::xGetLongTermRefPic(TComList& rcListPic, Int poc, Bool pocHasMsb) +{ + TComList::iterator iterPic = rcListPic.begin(); + TComPic* pcPic = *(iterPic); + TComPic* pcStPic = pcPic; + + Int pocCycle = 1 << getSPS()->getBitsForPOC(); + if (!pocHasMsb) + { + poc = poc & (pocCycle - 1); + } + + while ( iterPic != rcListPic.end() ) + { + pcPic = *(iterPic); + if (pcPic && pcPic->getPOC()!=this->getPOC() && pcPic->getSlice( 0 )->isReferenced()) + { + Int picPoc = pcPic->getPOC(); + if (!pocHasMsb) + { + picPoc = picPoc & (pocCycle - 1); + } + + if (poc == picPoc) + { + if(pcPic->getIsLongTerm()) + { + return pcPic; + } + else + { + pcStPic = pcPic; + } + break; + } + } + + iterPic++; + } + + return pcStPic; +} + +Void TComSlice::setRefPOCList () +{ + for (Int iDir = 0; iDir < NUM_REF_PIC_LIST_01; iDir++) + { + for (Int iNumRefIdx = 0; iNumRefIdx < m_aiNumRefIdx[iDir]; iNumRefIdx++) + { + m_aiRefPOCList[iDir][iNumRefIdx] = m_apcRefPicList[iDir][iNumRefIdx]->getPOC(); + } + } + +} + +Void TComSlice::setList1IdxToList0Idx() +{ + Int idxL0, idxL1; + for ( idxL1 = 0; idxL1 < getNumRefIdx( REF_PIC_LIST_1 ); idxL1++ ) + { + m_list1IdxToList0Idx[idxL1] = -1; + for ( idxL0 = 0; idxL0 < getNumRefIdx( REF_PIC_LIST_0 ); idxL0++ ) + { + if ( m_apcRefPicList[REF_PIC_LIST_0][idxL0]->getPOC() == m_apcRefPicList[REF_PIC_LIST_1][idxL1]->getPOC() ) + { + m_list1IdxToList0Idx[idxL1] = idxL0; + break; + } + } + } +} + +Void TComSlice::setRefPicList( TComList& rcListPic, Bool checkNumPocTotalCurr ) +{ + if (!checkNumPocTotalCurr) + { + if (m_eSliceType == I_SLICE) + { + ::memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList)); + ::memset( m_aiNumRefIdx, 0, sizeof ( m_aiNumRefIdx )); + + return; + } + + m_aiNumRefIdx[REF_PIC_LIST_0] = getNumRefIdx(REF_PIC_LIST_0); + m_aiNumRefIdx[REF_PIC_LIST_1] = getNumRefIdx(REF_PIC_LIST_1); + } + + TComPic* pcRefPic= NULL; + static const UInt MAX_NUM_NEGATIVE_PICTURES=16; + TComPic* RefPicSetStCurr0[MAX_NUM_NEGATIVE_PICTURES]; + TComPic* RefPicSetStCurr1[MAX_NUM_NEGATIVE_PICTURES]; + TComPic* RefPicSetLtCurr[MAX_NUM_NEGATIVE_PICTURES]; + UInt NumPocStCurr0 = 0; + UInt NumPocStCurr1 = 0; + UInt NumPocLtCurr = 0; + Int i; + + for(i=0; i < m_pcRPS->getNumberOfNegativePictures(); i++) + { + if(m_pcRPS->getUsed(i)) + { + pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i)); + pcRefPic->setIsLongTerm(0); + pcRefPic->getPicYuvRec()->extendPicBorder(); + RefPicSetStCurr0[NumPocStCurr0] = pcRefPic; + NumPocStCurr0++; + pcRefPic->setCheckLTMSBPresent(false); + } + } + + for(; i < m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures(); i++) + { + if(m_pcRPS->getUsed(i)) + { + pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i)); + pcRefPic->setIsLongTerm(0); + pcRefPic->getPicYuvRec()->extendPicBorder(); + RefPicSetStCurr1[NumPocStCurr1] = pcRefPic; + NumPocStCurr1++; + pcRefPic->setCheckLTMSBPresent(false); + } + } + + for(i = m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()+m_pcRPS->getNumberOfLongtermPictures()-1; i > m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()-1 ; i--) + { + if(m_pcRPS->getUsed(i)) + { + pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i)); + pcRefPic->setIsLongTerm(1); + pcRefPic->getPicYuvRec()->extendPicBorder(); + RefPicSetLtCurr[NumPocLtCurr] = pcRefPic; + NumPocLtCurr++; + } + if(pcRefPic==NULL) + { + pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i)); + } + pcRefPic->setCheckLTMSBPresent(m_pcRPS->getCheckLTMSBPresent(i)); + } + + // ref_pic_list_init + TComPic* rpsCurrList0[MAX_NUM_REF+1]; + TComPic* rpsCurrList1[MAX_NUM_REF+1]; + Int numPocTotalCurr = NumPocStCurr0 + NumPocStCurr1 + NumPocLtCurr; + + if (checkNumPocTotalCurr) + { + // The variable NumPocTotalCurr is derived as specified in subclause 7.4.7.2. It is a requirement of bitstream conformance that the following applies to the value of NumPocTotalCurr: + // - If the current picture is a BLA or CRA picture, the value of NumPocTotalCurr shall be equal to 0. + // - Otherwise, when the current picture contains a P or B slice, the value of NumPocTotalCurr shall not be equal to 0. + if (getRapPicFlag()) + { + assert(numPocTotalCurr == 0); + } + + if (m_eSliceType == I_SLICE) + { + ::memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList)); + ::memset( m_aiNumRefIdx, 0, sizeof ( m_aiNumRefIdx )); + + return; + } + + assert(numPocTotalCurr > 0); + + m_aiNumRefIdx[0] = getNumRefIdx(REF_PIC_LIST_0); + m_aiNumRefIdx[1] = getNumRefIdx(REF_PIC_LIST_1); + } + + Int cIdx = 0; + for ( i=0; i= 0 && cIdx < numPocTotalCurr); + m_apcRefPicList[REF_PIC_LIST_0][rIdx] = rpsCurrList0[ cIdx ]; + m_bIsUsedAsLongTerm[REF_PIC_LIST_0][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 ); + } + if ( m_eSliceType != B_SLICE ) + { + m_aiNumRefIdx[REF_PIC_LIST_1] = 0; + ::memset( m_apcRefPicList[REF_PIC_LIST_1], 0, sizeof(m_apcRefPicList[REF_PIC_LIST_1])); + } + else + { + for (Int rIdx = 0; rIdx < m_aiNumRefIdx[REF_PIC_LIST_1]; rIdx ++) + { + cIdx = m_RefPicListModification.getRefPicListModificationFlagL1() ? m_RefPicListModification.getRefPicSetIdxL1(rIdx) : rIdx % numPocTotalCurr; + assert(cIdx >= 0 && cIdx < numPocTotalCurr); + m_apcRefPicList[REF_PIC_LIST_1][rIdx] = rpsCurrList1[ cIdx ]; + m_bIsUsedAsLongTerm[REF_PIC_LIST_1][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 ); + } + } +} + +Int TComSlice::getNumRpsCurrTempList() +{ + Int numRpsCurrTempList = 0; + + if (m_eSliceType == I_SLICE) + { + return 0; + } + for(UInt i=0; i < m_pcRPS->getNumberOfNegativePictures()+ m_pcRPS->getNumberOfPositivePictures() + m_pcRPS->getNumberOfLongtermPictures(); i++) + { + if(m_pcRPS->getUsed(i)) + { + numRpsCurrTempList++; + } + } + return numRpsCurrTempList; +} + +Void TComSlice::initEqualRef() +{ + for (Int iDir = 0; iDir < NUM_REF_PIC_LIST_01; iDir++) + { + for (Int iRefIdx1 = 0; iRefIdx1 < MAX_NUM_REF; iRefIdx1++) + { + for (Int iRefIdx2 = iRefIdx1; iRefIdx2 < MAX_NUM_REF; iRefIdx2++) + { + m_abEqualRef[iDir][iRefIdx1][iRefIdx2] = m_abEqualRef[iDir][iRefIdx2][iRefIdx1] = (iRefIdx1 == iRefIdx2? true : false); + } + } + } +} + +Void TComSlice::checkColRefIdx(UInt curSliceIdx, TComPic* pic) +{ + Int i; + TComSlice* curSlice = pic->getSlice(curSliceIdx); + Int currColRefPOC = curSlice->getRefPOC( RefPicList(1 - curSlice->getColFromL0Flag()), curSlice->getColRefIdx()); + TComSlice* preSlice; + Int preColRefPOC; + for(i=curSliceIdx-1; i>=0; i--) + { + preSlice = pic->getSlice(i); + if(preSlice->getSliceType() != I_SLICE) + { + preColRefPOC = preSlice->getRefPOC( RefPicList(1 - preSlice->getColFromL0Flag()), preSlice->getColRefIdx()); + if(currColRefPOC != preColRefPOC) + { + printf("Collocated_ref_idx shall always be the same for all slices of a coded picture!\n"); + exit(EXIT_FAILURE); + } + else + { + break; + } + } + } +} + +Void TComSlice::checkCRA(TComReferencePictureSet *pReferencePictureSet, Int& pocCRA, NalUnitType& associatedIRAPType, TComList& rcListPic) +{ + for(Int i = 0; i < pReferencePictureSet->getNumberOfNegativePictures()+pReferencePictureSet->getNumberOfPositivePictures(); i++) + { + if(pocCRA < MAX_UINT && getPOC() > pocCRA) + { + assert(getPOC()+pReferencePictureSet->getDeltaPOC(i) >= pocCRA); + } + } + for(Int i = pReferencePictureSet->getNumberOfNegativePictures()+pReferencePictureSet->getNumberOfPositivePictures(); i < pReferencePictureSet->getNumberOfPictures(); i++) + { + if(pocCRA < MAX_UINT && getPOC() > pocCRA) + { + if (!pReferencePictureSet->getCheckLTMSBPresent(i)) + { + assert(xGetLongTermRefPic(rcListPic, pReferencePictureSet->getPOC(i), false)->getPOC() >= pocCRA); + } + else + { + assert(pReferencePictureSet->getPOC(i) >= pocCRA); + } + } + } + if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP ) // IDR picture found + { + pocCRA = getPOC(); + associatedIRAPType = getNalUnitType(); + } + else if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) // CRA picture found + { + pocCRA = getPOC(); + associatedIRAPType = getNalUnitType(); + } + else if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP ) // BLA picture found + { + pocCRA = getPOC(); + associatedIRAPType = getNalUnitType(); + } +} + +/** Function for marking the reference pictures when an IDR/CRA/CRANT/BLA/BLANT is encountered. + * \param pocCRA POC of the CRA/CRANT/BLA/BLANT picture + * \param bRefreshPending flag indicating if a deferred decoding refresh is pending + * \param rcListPic reference to the reference picture list + * This function marks the reference pictures as "unused for reference" in the following conditions. + * If the nal_unit_type is IDR/BLA/BLANT, all pictures in the reference picture list + * are marked as "unused for reference" + * If the nal_unit_type is BLA/BLANT, set the pocCRA to the temporal reference of the current picture. + * Otherwise + * If the bRefreshPending flag is true (a deferred decoding refresh is pending) and the current + * temporal reference is greater than the temporal reference of the latest CRA/CRANT/BLA/BLANT picture (pocCRA), + * mark all reference pictures except the latest CRA/CRANT/BLA/BLANT picture as "unused for reference" and set + * the bRefreshPending flag to false. + * If the nal_unit_type is CRA/CRANT, set the bRefreshPending flag to true and pocCRA to the temporal + * reference of the current picture. + * Note that the current picture is already placed in the reference list and its marking is not changed. + * If the current picture has a nal_ref_idc that is not 0, it will remain marked as "used for reference". + */ +Void TComSlice::decodingRefreshMarking(Int& pocCRA, Bool& bRefreshPending, TComList& rcListPic) +{ + TComPic* rpcPic; + Int pocCurr = getPOC(); + + if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP + || getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL + || getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP ) // IDR or BLA picture + { + // mark all pictures as not used for reference + TComList::iterator iterPic = rcListPic.begin(); + while (iterPic != rcListPic.end()) + { + rpcPic = *(iterPic); + rpcPic->setCurrSliceIdx(0); + if (rpcPic->getPOC() != pocCurr) rpcPic->getSlice(0)->setReferenced(false); + iterPic++; + } + if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP ) + { + pocCRA = pocCurr; + } +#if EFFICIENT_FIELD_IRAP + bRefreshPending = true; +#endif + } + else // CRA or No DR + { +#if EFFICIENT_FIELD_IRAP + if(getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_IDR_N_LP || getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL) + { + if (bRefreshPending==true && pocCurr > m_iLastIDR) // IDR reference marking pending + { + TComList::iterator iterPic = rcListPic.begin(); + while (iterPic != rcListPic.end()) + { + rpcPic = *(iterPic); + if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != m_iLastIDR) + { + rpcPic->getSlice(0)->setReferenced(false); + } + iterPic++; + } + bRefreshPending = false; + } + } + else + { +#endif + if (bRefreshPending==true && pocCurr > pocCRA) // CRA reference marking pending + { + TComList::iterator iterPic = rcListPic.begin(); + while (iterPic != rcListPic.end()) + { + rpcPic = *(iterPic); + if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != pocCRA) + { + rpcPic->getSlice(0)->setReferenced(false); + } + iterPic++; + } + bRefreshPending = false; + } +#if EFFICIENT_FIELD_IRAP + } +#endif + if ( getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) // CRA picture found + { + bRefreshPending = true; + pocCRA = pocCurr; + } + } +} + +Void TComSlice::copySliceInfo(TComSlice *pSrc) +{ + assert( pSrc != NULL ); + + Int i, j, k; + + m_iPOC = pSrc->m_iPOC; + m_eNalUnitType = pSrc->m_eNalUnitType; + m_eSliceType = pSrc->m_eSliceType; + m_iSliceQp = pSrc->m_iSliceQp; +#if ADAPTIVE_QP_SELECTION + m_iSliceQpBase = pSrc->m_iSliceQpBase; +#endif + m_ChromaQpAdjEnabled = pSrc->m_ChromaQpAdjEnabled; + m_deblockingFilterDisable = pSrc->m_deblockingFilterDisable; + m_deblockingFilterOverrideFlag = pSrc->m_deblockingFilterOverrideFlag; + m_deblockingFilterBetaOffsetDiv2 = pSrc->m_deblockingFilterBetaOffsetDiv2; + m_deblockingFilterTcOffsetDiv2 = pSrc->m_deblockingFilterTcOffsetDiv2; + + for (i = 0; i < NUM_REF_PIC_LIST_01; i++) + { + m_aiNumRefIdx[i] = pSrc->m_aiNumRefIdx[i]; + } + + for (i = 0; i < MAX_NUM_REF; i++) + { + m_list1IdxToList0Idx[i] = pSrc->m_list1IdxToList0Idx[i]; + } + + m_bCheckLDC = pSrc->m_bCheckLDC; + m_iSliceQpDelta = pSrc->m_iSliceQpDelta; + for (UInt component = 0; component < MAX_NUM_COMPONENT; component++) m_iSliceChromaQpDelta[component] = pSrc->m_iSliceChromaQpDelta[component]; + for (i = 0; i < NUM_REF_PIC_LIST_01; i++) + { + for (j = 0; j < MAX_NUM_REF; j++) + { + m_apcRefPicList[i][j] = pSrc->m_apcRefPicList[i][j]; + m_aiRefPOCList[i][j] = pSrc->m_aiRefPOCList[i][j]; + m_bIsUsedAsLongTerm[i][j] = pSrc->m_bIsUsedAsLongTerm[i][j]; + } + m_bIsUsedAsLongTerm[i][MAX_NUM_REF] = pSrc->m_bIsUsedAsLongTerm[i][MAX_NUM_REF]; + } + m_iDepth = pSrc->m_iDepth; + + // referenced slice + m_bRefenced = pSrc->m_bRefenced; + + // access channel + m_pcSPS = pSrc->m_pcSPS; + m_pcPPS = pSrc->m_pcPPS; + m_pcRPS = pSrc->m_pcRPS; + m_iLastIDR = pSrc->m_iLastIDR; + + m_pcPic = pSrc->m_pcPic; + + m_colFromL0Flag = pSrc->m_colFromL0Flag; + m_colRefIdx = pSrc->m_colRefIdx; + + setLambdas(pSrc->getLambdas()); + + for (i = 0; i < NUM_REF_PIC_LIST_01; i++) + { + for (j = 0; j < MAX_NUM_REF; j++) + { + for (k =0; k < MAX_NUM_REF; k++) + { + m_abEqualRef[i][j][k] = pSrc->m_abEqualRef[i][j][k]; + } + } + } + + m_uiTLayer = pSrc->m_uiTLayer; + m_bTLayerSwitchingFlag = pSrc->m_bTLayerSwitchingFlag; + + m_sliceMode = pSrc->m_sliceMode; + m_sliceArgument = pSrc->m_sliceArgument; + m_sliceCurStartCtuTsAddr = pSrc->m_sliceCurStartCtuTsAddr; + m_sliceCurEndCtuTsAddr = pSrc->m_sliceCurEndCtuTsAddr; + m_sliceIdx = pSrc->m_sliceIdx; + m_sliceSegmentMode = pSrc->m_sliceSegmentMode; + m_sliceSegmentArgument = pSrc->m_sliceSegmentArgument; + m_sliceSegmentCurStartCtuTsAddr = pSrc->m_sliceSegmentCurStartCtuTsAddr; + m_sliceSegmentCurEndCtuTsAddr = pSrc->m_sliceSegmentCurEndCtuTsAddr; + m_nextSlice = pSrc->m_nextSlice; + m_nextSliceSegment = pSrc->m_nextSliceSegment; + + for ( UInt e=0 ; em_weightPredTable[e][n], sizeof(WPScalingParam)*MAX_NUM_COMPONENT ); + } + } + + for( UInt ch = 0 ; ch < MAX_NUM_CHANNEL_TYPE; ch++) + { + m_saoEnabledFlag[ch] = pSrc->m_saoEnabledFlag[ch]; + } + + m_cabacInitFlag = pSrc->m_cabacInitFlag; + + m_bLMvdL1Zero = pSrc->m_bLMvdL1Zero; + m_LFCrossSliceBoundaryFlag = pSrc->m_LFCrossSliceBoundaryFlag; + m_enableTMVPFlag = pSrc->m_enableTMVPFlag; + m_maxNumMergeCand = pSrc->m_maxNumMergeCand; +} + + +Int TComSlice::m_prevTid0POC = 0; + +/** Function for setting the slice's temporal layer ID and corresponding temporal_layer_switching_point_flag. + * \param uiTLayer Temporal layer ID of the current slice + * The decoder calls this function to set temporal_layer_switching_point_flag for each temporal layer based on + * the SPS's temporal_id_nesting_flag and the parsed PPS. Then, current slice's temporal layer ID and + * temporal_layer_switching_point_flag is set accordingly. + */ +Void TComSlice::setTLayerInfo( UInt uiTLayer ) +{ + m_uiTLayer = uiTLayer; +} + +/** Function for checking if this is a switching-point +*/ +Bool TComSlice::isTemporalLayerSwitchingPoint(TComList& rcListPic) +{ + TComPic* rpcPic; + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + if(rpcPic->getSlice(0)->isReferenced() && rpcPic->getPOC() != getPOC()) + { + if(rpcPic->getTLayer() >= getTLayer()) + { + return false; + } + } + } + return true; +} + +/** Function for checking if this is a STSA candidate + */ +Bool TComSlice::isStepwiseTemporalLayerSwitchingPointCandidate(TComList& rcListPic) +{ + TComPic* rpcPic; + + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + if(rpcPic->getSlice(0)->isReferenced() && (rpcPic->getUsedByCurr()==true) && rpcPic->getPOC() != getPOC()) + { + if(rpcPic->getTLayer() >= getTLayer()) + { + return false; + } + } + } + return true; +} + + +Void TComSlice::checkLeadingPictureRestrictions(TComList& rcListPic) +{ + TComPic* rpcPic; + + Int nalUnitType = this->getNalUnitType(); + + // When a picture is a leading picture, it shall be a RADL or RASL picture. + if(this->getAssociatedIRAPPOC() > this->getPOC()) + { + // Do not check IRAP pictures since they may get a POC lower than their associated IRAP + if(nalUnitType < NAL_UNIT_CODED_SLICE_BLA_W_LP || + nalUnitType > NAL_UNIT_RESERVED_IRAP_VCL23) + { + assert(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_R); + } + } + + // When a picture is a trailing picture, it shall not be a RADL or RASL picture. + if(this->getAssociatedIRAPPOC() < this->getPOC()) + { + assert(nalUnitType != NAL_UNIT_CODED_SLICE_RASL_N && + nalUnitType != NAL_UNIT_CODED_SLICE_RASL_R && + nalUnitType != NAL_UNIT_CODED_SLICE_RADL_N && + nalUnitType != NAL_UNIT_CODED_SLICE_RADL_R); + } + + // No RASL pictures shall be present in the bitstream that are associated + // with a BLA picture having nal_unit_type equal to BLA_W_RADL or BLA_N_LP. + if(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R) + { + assert(this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_BLA_W_RADL && + this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_BLA_N_LP); + } + + // No RASL pictures shall be present in the bitstream that are associated with + // an IDR picture. + if(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R) + { + assert(this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_IDR_N_LP && + this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_IDR_W_RADL); + } + + // No RADL pictures shall be present in the bitstream that are associated with + // a BLA picture having nal_unit_type equal to BLA_N_LP or that are associated + // with an IDR picture having nal_unit_type equal to IDR_N_LP. + if(nalUnitType == NAL_UNIT_CODED_SLICE_RADL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_R) + { + assert(this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_BLA_N_LP && + this->getAssociatedIRAPType() != NAL_UNIT_CODED_SLICE_IDR_N_LP); + } + + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); +#if BUGFIX_INTRAPERIOD + if(!rpcPic->getReconMark()) + { + continue; + } +#endif + if (rpcPic->getPOC() == this->getPOC()) + { + continue; + } + + // Any picture that has PicOutputFlag equal to 1 that precedes an IRAP picture + // in decoding order shall precede the IRAP picture in output order. + // (Note that any picture following in output order would be present in the DPB) + if(rpcPic->getSlice(0)->getPicOutputFlag() == 1 && !this->getNoOutputPriorPicsFlag()) + { + if(nalUnitType == NAL_UNIT_CODED_SLICE_BLA_N_LP || + nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_LP || + nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_RADL || + nalUnitType == NAL_UNIT_CODED_SLICE_CRA || + nalUnitType == NAL_UNIT_CODED_SLICE_IDR_N_LP || + nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL) + { + assert(rpcPic->getPOC() < this->getPOC()); + } + } + + // Any picture that has PicOutputFlag equal to 1 that precedes an IRAP picture + // in decoding order shall precede any RADL picture associated with the IRAP + // picture in output order. + if(rpcPic->getSlice(0)->getPicOutputFlag() == 1) + { + if((nalUnitType == NAL_UNIT_CODED_SLICE_RADL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_R)) + { + // rpcPic precedes the IRAP in decoding order + if(this->getAssociatedIRAPPOC() > rpcPic->getSlice(0)->getAssociatedIRAPPOC()) + { + // rpcPic must not be the IRAP picture + if(this->getAssociatedIRAPPOC() != rpcPic->getPOC()) + { + assert(rpcPic->getPOC() < this->getPOC()); + } + } + } + } + + // When a picture is a leading picture, it shall precede, in decoding order, + // all trailing pictures that are associated with the same IRAP picture. + if(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RADL_R) + { + if(rpcPic->getSlice(0)->getAssociatedIRAPPOC() == this->getAssociatedIRAPPOC()) + { + // rpcPic is a picture that preceded the leading in decoding order since it exist in the DPB + // rpcPic would violate the constraint if it was a trailing picture + assert(rpcPic->getPOC() <= this->getAssociatedIRAPPOC()); + } + } + + // Any RASL picture associated with a CRA or BLA picture shall precede any + // RADL picture associated with the CRA or BLA picture in output order + if(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R) + { + if((this->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_BLA_N_LP || + this->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_BLA_W_LP || + this->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL || + this->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_CRA) && + this->getAssociatedIRAPPOC() == rpcPic->getSlice(0)->getAssociatedIRAPPOC()) + { + if(rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_N || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_R) + { + assert(rpcPic->getPOC() > this->getPOC()); + } + } + } + + // Any RASL picture associated with a CRA picture shall follow, in output + // order, any IRAP picture that precedes the CRA picture in decoding order. + if(nalUnitType == NAL_UNIT_CODED_SLICE_RASL_N || + nalUnitType == NAL_UNIT_CODED_SLICE_RASL_R) + { + if(this->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_CRA) + { + if(rpcPic->getSlice(0)->getPOC() < this->getAssociatedIRAPPOC() && + (rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || + rpcPic->getSlice(0)->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA)) + { + assert(this->getPOC() > rpcPic->getSlice(0)->getPOC()); + } + } + } + } +} + + + +/** Function for applying picture marking based on the Reference Picture Set in pReferencePictureSet. +*/ +Void TComSlice::applyReferencePictureSet( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet) +{ + TComPic* rpcPic; + Int i, isReference; + + checkLeadingPictureRestrictions(rcListPic); + + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + + if(!rpcPic->getSlice( 0 )->isReferenced()) + { + continue; + } + + isReference = 0; + // loop through all pictures in the Reference Picture Set + // to see if the picture should be kept as reference picture + for(i=0;igetNumberOfPositivePictures()+pReferencePictureSet->getNumberOfNegativePictures();i++) + { + if(!rpcPic->getIsLongTerm() && rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i)) + { + isReference = 1; + rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i)); + rpcPic->setIsLongTerm(0); + } + } + for(;igetNumberOfPictures();i++) + { + if(pReferencePictureSet->getCheckLTMSBPresent(i)==true) + { + if(rpcPic->getIsLongTerm() && (rpcPic->getPicSym()->getSlice(0)->getPOC()) == pReferencePictureSet->getPOC(i)) + { + isReference = 1; + rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i)); + } + } + else + { + Int pocCycle = 1<getPicSym()->getSlice(0)->getSPS()->getBitsForPOC(); + Int curPoc = rpcPic->getPicSym()->getSlice(0)->getPOC() & (pocCycle-1); + Int refPoc = pReferencePictureSet->getPOC(i) & (pocCycle-1); + if(rpcPic->getIsLongTerm() && curPoc == refPoc) + { + isReference = 1; + rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i)); + } + } + + } + // mark the picture as "unused for reference" if it is not in + // the Reference Picture Set + if(rpcPic->getPicSym()->getSlice(0)->getPOC() != this->getPOC() && isReference == 0) + { + rpcPic->getSlice( 0 )->setReferenced( false ); + rpcPic->setUsedByCurr(0); + rpcPic->setIsLongTerm(0); + } + //check that pictures of higher temporal layers are not used + assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getUsedByCurr()==0||rpcPic->getTLayer()<=this->getTLayer()); + //check that pictures of higher or equal temporal layer are not in the RPS if the current picture is a TSA picture + if(this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_R || this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_N) + { + assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getTLayer()getTLayer()); + } + //check that pictures marked as temporal layer non-reference pictures are not used for reference + if(rpcPic->getPicSym()->getSlice(0)->getPOC() != this->getPOC() && rpcPic->getTLayer()==this->getTLayer()) + { + assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getUsedByCurr()==0||rpcPic->getSlice( 0 )->getTemporalLayerNonReferenceFlag()==false); + } + } +} + +/** Function for applying picture marking based on the Reference Picture Set in pReferencePictureSet. +*/ +#if ALLOW_RECOVERY_POINT_AS_RAP +Int TComSlice::checkThatAllRefPicsAreAvailable( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool printErrors, Int pocRandomAccess, Bool bUseRecoveryPoint) +#else +Int TComSlice::checkThatAllRefPicsAreAvailable( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool printErrors, Int pocRandomAccess) +#endif +{ +#if ALLOW_RECOVERY_POINT_AS_RAP + Int atLeastOneUnabledByRecoveryPoint = 0; + Int atLeastOneFlushedByPreviousIDR = 0; +#endif + TComPic* rpcPic; + Int i, isAvailable; + Int atLeastOneLost = 0; + Int atLeastOneRemoved = 0; + Int iPocLost = 0; + + // loop through all long-term pictures in the Reference Picture Set + // to see if the picture should be kept as reference picture + for(i=pReferencePictureSet->getNumberOfNegativePictures()+pReferencePictureSet->getNumberOfPositivePictures();igetNumberOfPictures();i++) + { + isAvailable = 0; + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + if(pReferencePictureSet->getCheckLTMSBPresent(i)==true) + { + if(rpcPic->getIsLongTerm() && (rpcPic->getPicSym()->getSlice(0)->getPOC()) == pReferencePictureSet->getPOC(i) && rpcPic->getSlice(0)->isReferenced()) + { +#if ALLOW_RECOVERY_POINT_AS_RAP + if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) + { + isAvailable = 0; + } + else + { + isAvailable = 1; + } +#else + isAvailable = 1; +#endif + } + } + else + { + Int pocCycle = 1<getPicSym()->getSlice(0)->getSPS()->getBitsForPOC(); + Int curPoc = rpcPic->getPicSym()->getSlice(0)->getPOC() & (pocCycle-1); + Int refPoc = pReferencePictureSet->getPOC(i) & (pocCycle-1); + if(rpcPic->getIsLongTerm() && curPoc == refPoc && rpcPic->getSlice(0)->isReferenced()) + { +#if ALLOW_RECOVERY_POINT_AS_RAP + if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) + { + isAvailable = 0; + } + else + { + isAvailable = 1; + } +#else + isAvailable = 1; +#endif + } + } + } + // if there was no such long-term check the short terms + if(!isAvailable) + { + iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + + Int pocCycle = 1 << rpcPic->getPicSym()->getSlice(0)->getSPS()->getBitsForPOC(); + Int curPoc = rpcPic->getPicSym()->getSlice(0)->getPOC(); + Int refPoc = pReferencePictureSet->getPOC(i); + if (!pReferencePictureSet->getCheckLTMSBPresent(i)) + { + curPoc = curPoc & (pocCycle - 1); + refPoc = refPoc & (pocCycle - 1); + } + + if (rpcPic->getSlice(0)->isReferenced() && curPoc == refPoc) + { +#if ALLOW_RECOVERY_POINT_AS_RAP + if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) + { + isAvailable = 0; + } + else + { + isAvailable = 1; + rpcPic->setIsLongTerm(1); + break; + } +#else + isAvailable = 1; + rpcPic->setIsLongTerm(1); + break; +#endif + } + } + } + // report that a picture is lost if it is in the Reference Picture Set + // but not available as reference picture + if(isAvailable == 0) + { + if (this->getPOC() + pReferencePictureSet->getDeltaPOC(i) >= pocRandomAccess) + { + if(!pReferencePictureSet->getUsed(i) ) + { + if(printErrors) + { + printf("\nLong-term reference picture with POC = %3d seems to have been removed or not correctly decoded.", this->getPOC() + pReferencePictureSet->getDeltaPOC(i)); + } + atLeastOneRemoved = 1; + } + else + { + if(printErrors) + { + printf("\nLong-term reference picture with POC = %3d is lost or not correctly decoded!", this->getPOC() + pReferencePictureSet->getDeltaPOC(i)); + } + atLeastOneLost = 1; + iPocLost=this->getPOC() + pReferencePictureSet->getDeltaPOC(i); + } + } +#if ALLOW_RECOVERY_POINT_AS_RAP + else if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess) + { + atLeastOneUnabledByRecoveryPoint = 1; + } + else if(bUseRecoveryPoint && (this->getAssociatedIRAPType()==NAL_UNIT_CODED_SLICE_IDR_N_LP || this->getAssociatedIRAPType()==NAL_UNIT_CODED_SLICE_IDR_W_RADL)) + { + atLeastOneFlushedByPreviousIDR = 1; + } +#endif + } + } + // loop through all short-term pictures in the Reference Picture Set + // to see if the picture should be kept as reference picture + for(i=0;igetNumberOfNegativePictures()+pReferencePictureSet->getNumberOfPositivePictures();i++) + { + isAvailable = 0; + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + + if(!rpcPic->getIsLongTerm() && rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i) && rpcPic->getSlice(0)->isReferenced()) + { +#if ALLOW_RECOVERY_POINT_AS_RAP + if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) + { + isAvailable = 0; + } + else + { + isAvailable = 1; + } +#else + isAvailable = 1; +#endif + } + } + // report that a picture is lost if it is in the Reference Picture Set + // but not available as reference picture + if(isAvailable == 0) + { + if (this->getPOC() + pReferencePictureSet->getDeltaPOC(i) >= pocRandomAccess) + { + if(!pReferencePictureSet->getUsed(i) ) + { + if(printErrors) + { + printf("\nShort-term reference picture with POC = %3d seems to have been removed or not correctly decoded.", this->getPOC() + pReferencePictureSet->getDeltaPOC(i)); + } + atLeastOneRemoved = 1; + } + else + { + if(printErrors) + { + printf("\nShort-term reference picture with POC = %3d is lost or not correctly decoded!", this->getPOC() + pReferencePictureSet->getDeltaPOC(i)); + } + atLeastOneLost = 1; + iPocLost=this->getPOC() + pReferencePictureSet->getDeltaPOC(i); + } + } +#if ALLOW_RECOVERY_POINT_AS_RAP + else if(bUseRecoveryPoint && this->getPOC() > pocRandomAccess) + { + atLeastOneUnabledByRecoveryPoint = 1; + } + else if(bUseRecoveryPoint && (this->getAssociatedIRAPType()==NAL_UNIT_CODED_SLICE_IDR_N_LP || this->getAssociatedIRAPType()==NAL_UNIT_CODED_SLICE_IDR_W_RADL)) + { + atLeastOneFlushedByPreviousIDR = 1; + } +#endif + } + } + +#if ALLOW_RECOVERY_POINT_AS_RAP + if(atLeastOneUnabledByRecoveryPoint || atLeastOneFlushedByPreviousIDR) + { + return -1; + } +#endif + if(atLeastOneLost) + { + return iPocLost+1; + } + if(atLeastOneRemoved) + { + return -2; + } + else + { + return 0; + } +} + +/** Function for constructing an explicit Reference Picture Set out of the available pictures in a referenced Reference Picture Set +*/ +#if ALLOW_RECOVERY_POINT_AS_RAP +Void TComSlice::createExplicitReferencePictureSetFromReference( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP, Int pocRandomAccess, Bool bUseRecoveryPoint) +#else +Void TComSlice::createExplicitReferencePictureSetFromReference( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP) +#endif +{ + TComPic* rpcPic; + Int i, j; + Int k = 0; + Int nrOfNegativePictures = 0; + Int nrOfPositivePictures = 0; + TComReferencePictureSet* pcRPS = this->getLocalRPS(); +#if EFFICIENT_FIELD_IRAP + Bool irapIsInRPS = false; +#endif + + // loop through all pictures in the Reference Picture Set + for(i=0;igetNumberOfPictures();i++) + { + j = 0; + // loop through all pictures in the reference picture buffer + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + j++; + rpcPic = *(iterPic++); + + if(rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i) && rpcPic->getSlice(0)->isReferenced()) + { + // This picture exists as a reference picture + // and should be added to the explicit Reference Picture Set + pcRPS->setDeltaPOC(k, pReferencePictureSet->getDeltaPOC(i)); + pcRPS->setUsed(k, pReferencePictureSet->getUsed(i) && (!isRAP)); +#if ALLOW_RECOVERY_POINT_AS_RAP + pcRPS->setUsed(k, pcRPS->getUsed(k) && !(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) ); +#endif + + if(pcRPS->getDeltaPOC(k) < 0) + { + nrOfNegativePictures++; + } + else + { +#if EFFICIENT_FIELD_IRAP + if(rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getAssociatedIRAPPOC() && this->getAssociatedIRAPPOC() == this->getPOC()+1) + { + irapIsInRPS = true; + } +#endif + nrOfPositivePictures++; + } + k++; + } + } + } + +#if EFFICIENT_FIELD_IRAP + Bool useNewRPS = false; + // if current picture is complimentary field associated to IRAP, add the IRAP to its RPS. + if(m_pcPic->isField() && !irapIsInRPS) + { + TComList::iterator iterPic = rcListPic.begin(); + while ( iterPic != rcListPic.end()) + { + rpcPic = *(iterPic++); + if(rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getAssociatedIRAPPOC() && this->getAssociatedIRAPPOC() == this->getPOC()+1) + { + pcRPS->setDeltaPOC(k, 1); + pcRPS->setUsed(k, true); + nrOfPositivePictures++; + k ++; + useNewRPS = true; + } + } + } +#endif + pcRPS->setNumberOfNegativePictures(nrOfNegativePictures); + pcRPS->setNumberOfPositivePictures(nrOfPositivePictures); + pcRPS->setNumberOfPictures(nrOfNegativePictures+nrOfPositivePictures); + // This is a simplistic inter rps example. A smarter encoder will look for a better reference RPS to do the + // inter RPS prediction with. Here we just use the reference used by pReferencePictureSet. + // If pReferencePictureSet is not inter_RPS_predicted, then inter_RPS_prediction is for the current RPS also disabled. + if (!pReferencePictureSet->getInterRPSPrediction() +#if EFFICIENT_FIELD_IRAP + || useNewRPS +#endif + ) + { + pcRPS->setInterRPSPrediction(false); + pcRPS->setNumRefIdc(0); + } + else + { + Int rIdx = this->getRPSidx() - pReferencePictureSet->getDeltaRIdxMinus1() - 1; + Int deltaRPS = pReferencePictureSet->getDeltaRPS(); + TComReferencePictureSet* pcRefRPS = this->getSPS()->getRPSList()->getReferencePictureSet(rIdx); + Int iRefPics = pcRefRPS->getNumberOfPictures(); + Int iNewIdc=0; + for(i=0; i<= iRefPics; i++) + { + Int deltaPOC = ((i != iRefPics)? pcRefRPS->getDeltaPOC(i) : 0); // check if the reference abs POC is >= 0 + Int iRefIdc = 0; + for (j=0; j < pcRPS->getNumberOfPictures(); j++) // loop through the pictures in the new RPS + { + if ( (deltaPOC + deltaRPS) == pcRPS->getDeltaPOC(j)) + { + if (pcRPS->getUsed(j)) + { + iRefIdc = 1; + } + else + { + iRefIdc = 2; + } + } + } + pcRPS->setRefIdc(i, iRefIdc); + iNewIdc++; + } + pcRPS->setInterRPSPrediction(true); + pcRPS->setNumRefIdc(iNewIdc); + pcRPS->setDeltaRPS(deltaRPS); + pcRPS->setDeltaRIdxMinus1(pReferencePictureSet->getDeltaRIdxMinus1() + this->getSPS()->getRPSList()->getNumberOfReferencePictureSets() - this->getRPSidx()); + } + + this->setRPS(pcRPS); + this->setRPSidx(-1); +} + +/** get AC and DC values for weighted pred + * \param *wp + * \returns Void + */ +Void TComSlice::getWpAcDcParam(WPACDCParam *&wp) +{ + wp = m_weightACDCParam; +} + +/** init AC and DC values for weighted pred + * \returns Void + */ +Void TComSlice::initWpAcDcParam() +{ + for(Int iComp = 0; iComp < MAX_NUM_COMPONENT; iComp++ ) + { + m_weightACDCParam[iComp].iAC = 0; + m_weightACDCParam[iComp].iDC = 0; + } +} + +/** get WP tables for weighted pred + * \param RefPicList + * \param iRefIdx + * \param *&WPScalingParam + * \returns Void + */ +Void TComSlice::getWpScaling( RefPicList e, Int iRefIdx, WPScalingParam *&wp ) +{ + assert (ebPresentFlag = false; + pwp->uiLog2WeightDenom = 0; + pwp->uiLog2WeightDenom = 0; + pwp->iWeight = 1; + pwp->iOffset = 0; + } + } + } +} + +/** init WP table + * \returns Void + */ +Void TComSlice::initWpScaling() +{ + const Bool bUseHighPrecisionPredictionWeighting = getSPS()->getUseHighPrecisionPredictionWeighting(); + for ( Int e=0 ; ebPresentFlag ) + { + // Inferring values not present : + pwp->iWeight = (1 << pwp->uiLog2WeightDenom); + pwp->iOffset = 0; + } + + const Int offsetScalingFactor = bUseHighPrecisionPredictionWeighting ? 1 : (1 << (g_bitDepth[toChannelType(ComponentID(yuv))]-8)); + + pwp->w = pwp->iWeight; + pwp->o = pwp->iOffset * offsetScalingFactor; //NOTE: This value of the ".o" variable is never used - .o is set immediately before it gets used + pwp->shift = pwp->uiLog2WeightDenom; + pwp->round = (pwp->uiLog2WeightDenom>=1) ? (1 << (pwp->uiLog2WeightDenom-1)) : (0); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Video parameter set (VPS) +// ------------------------------------------------------------------------------------------------ +TComVPS::TComVPS() +: m_VPSId ( 0) +, m_uiMaxTLayers ( 1) +, m_uiMaxLayers ( 1) +, m_bTemporalIdNestingFlag (false) +, m_numHrdParameters ( 0) +, m_maxNuhReservedZeroLayerId ( 0) +, m_hrdParameters (NULL) +, m_hrdOpSetIdx (NULL) +, m_cprmsPresentFlag (NULL) +{ + + for( Int i = 0; i < MAX_TLAYER; i++) + { + m_numReorderPics[i] = 0; + m_uiMaxDecPicBuffering[i] = 1; + m_uiMaxLatencyIncrease[i] = 0; + } +} + +TComVPS::~TComVPS() +{ + if( m_hrdParameters != NULL ) delete[] m_hrdParameters; + if( m_hrdOpSetIdx != NULL ) delete[] m_hrdOpSetIdx; + if( m_cprmsPresentFlag != NULL ) delete[] m_cprmsPresentFlag; +} + +// ------------------------------------------------------------------------------------------------ +// Sequence parameter set (SPS) +// ------------------------------------------------------------------------------------------------ + +TComSPS::TComSPS() +: m_SPSId ( 0) +, m_VPSId ( 0) +, m_chromaFormatIdc (CHROMA_420) +, m_uiMaxTLayers ( 1) +// Structure +, m_picWidthInLumaSamples (352) +, m_picHeightInLumaSamples (288) +, m_log2MinCodingBlockSize ( 0) +, m_log2DiffMaxMinCodingBlockSize(0) +, m_uiMaxCUWidth ( 32) +, m_uiMaxCUHeight ( 32) +, m_uiMaxCUDepth ( 3) +, m_bLongTermRefsPresent (false) +, m_uiQuadtreeTULog2MaxSize ( 0) +, m_uiQuadtreeTULog2MinSize ( 0) +, m_uiQuadtreeTUMaxDepthInter ( 0) +, m_uiQuadtreeTUMaxDepthIntra ( 0) +// Tool list +, m_usePCM (false) +, m_pcmLog2MaxSize ( 5) +, m_uiPCMLog2MinSize ( 7) +, m_useExtendedPrecision (false) +, m_useHighPrecisionPredictionWeighting(false) +, m_useResidualRotation (false) +, m_useSingleSignificanceMapContext(false) +, m_useGolombRiceParameterAdaptation(false) +, m_alignCABACBeforeBypass (false) +, m_bPCMFilterDisableFlag (false) +, m_disableIntraReferenceSmoothing(false) +, m_uiBitsForPOC ( 8) +, m_numLongTermRefPicSPS ( 0) +, m_uiMaxTrSize ( 32) +, m_bUseSAO (false) +, m_bTemporalIdNestingFlag (false) +, m_scalingListEnabledFlag (false) +, m_useStrongIntraSmoothing (false) +, m_vuiParametersPresentFlag (false) +, m_vuiParameters () +{ + for(Int ch=0; chgetHrdParameters(); + + TimingInfo *timingInfo = vui->getTimingInfo(); + timingInfo->setTimingInfoPresentFlag( true ); + switch( frameRate ) + { + case 24: + timingInfo->setNumUnitsInTick( 1125000 ); timingInfo->setTimeScale ( 27000000 ); + break; + case 25: + timingInfo->setNumUnitsInTick( 1080000 ); timingInfo->setTimeScale ( 27000000 ); + break; + case 30: + timingInfo->setNumUnitsInTick( 900900 ); timingInfo->setTimeScale ( 27000000 ); + break; + case 50: + timingInfo->setNumUnitsInTick( 540000 ); timingInfo->setTimeScale ( 27000000 ); + break; + case 60: + timingInfo->setNumUnitsInTick( 450450 ); timingInfo->setTimeScale ( 27000000 ); + break; + default: + timingInfo->setNumUnitsInTick( 1001 ); timingInfo->setTimeScale ( 60000 ); + break; + } + + Bool rateCnt = ( bitRate > 0 ); + hrd->setNalHrdParametersPresentFlag( rateCnt ); + hrd->setVclHrdParametersPresentFlag( rateCnt ); + + hrd->setSubPicCpbParamsPresentFlag( ( numDU > 1 ) ); + + if( hrd->getSubPicCpbParamsPresentFlag() ) + { + hrd->setTickDivisorMinus2( 100 - 2 ); // + hrd->setDuCpbRemovalDelayLengthMinus1( 7 ); // 8-bit precision ( plus 1 for last DU in AU ) + hrd->setSubPicCpbParamsInPicTimingSEIFlag( true ); + hrd->setDpbOutputDelayDuLengthMinus1( 5 + 7 ); // With sub-clock tick factor of 100, at least 7 bits to have the same value as AU dpb delay + } + else + { + hrd->setSubPicCpbParamsInPicTimingSEIFlag( false ); + } + + hrd->setBitRateScale( 4 ); // in units of 2~( 6 + 4 ) = 1,024 bps + hrd->setCpbSizeScale( 6 ); // in units of 2~( 4 + 4 ) = 1,024 bit + hrd->setDuCpbSizeScale( 6 ); // in units of 2~( 4 + 4 ) = 1,024 bit + + hrd->setInitialCpbRemovalDelayLengthMinus1(15); // assuming 0.5 sec, log2( 90,000 * 0.5 ) = 16-bit + if( randomAccess ) + { + hrd->setCpbRemovalDelayLengthMinus1(5); // 32 = 2^5 (plus 1) + hrd->setDpbOutputDelayLengthMinus1 (5); // 32 + 3 = 2^6 + } + else + { + hrd->setCpbRemovalDelayLengthMinus1(9); // max. 2^10 + hrd->setDpbOutputDelayLengthMinus1 (9); // max. 2^10 + } + +/* + Note: only the case of "vps_max_temporal_layers_minus1 = 0" is supported. +*/ + Int i, j; + UInt bitrateValue, cpbSizeValue; + UInt duCpbSizeValue; + UInt duBitRateValue = 0; + + for( i = 0; i < MAX_TLAYER; i ++ ) + { + hrd->setFixedPicRateFlag( i, 1 ); + hrd->setPicDurationInTcMinus1( i, 0 ); + hrd->setLowDelayHrdFlag( i, 0 ); + hrd->setCpbCntMinus1( i, 0 ); + + bitrateValue = bitRate; + cpbSizeValue = bitRate; // 1 second + duCpbSizeValue = bitRate/numDU; + duBitRateValue = bitRate; + + for( j = 0; j < ( hrd->getCpbCntMinus1( i ) + 1 ); j ++ ) + { + hrd->setBitRateValueMinus1( i, j, 0, ( bitrateValue - 1 ) ); + hrd->setCpbSizeValueMinus1( i, j, 0, ( cpbSizeValue - 1 ) ); + hrd->setDuCpbSizeValueMinus1( i, j, 0, ( duCpbSizeValue - 1 ) ); + hrd->setCbrFlag( i, j, 0, ( j == 0 ) ); + + hrd->setBitRateValueMinus1( i, j, 1, ( bitrateValue - 1) ); + hrd->setCpbSizeValueMinus1( i, j, 1, ( cpbSizeValue - 1 ) ); + hrd->setDuCpbSizeValueMinus1( i, j, 1, ( duCpbSizeValue - 1 ) ); + hrd->setDuBitRateValueMinus1( i, j, 1, ( duBitRateValue - 1 ) ); + hrd->setCbrFlag( i, j, 1, ( j == 0 ) ); + } + } +} + +const Int TComSPS::m_winUnitX[]={1,2,2,1}; +const Int TComSPS::m_winUnitY[]={1,2,1,1}; + +TComPPS::TComPPS() +: m_PPSId (0) +, m_SPSId (0) +, m_picInitQPMinus26 (0) +, m_useDQP (false) +, m_bConstrainedIntraPred (false) +, m_bSliceChromaQpFlag (false) +, m_pcSPS (NULL) +, m_uiMaxCuDQPDepth (0) +, m_uiMinCuDQPSize (0) +, m_MaxCuChromaQpAdjDepth (0) +, m_MinCuChromaQpAdjSize (0) +, m_ChromaQpAdjTableSize (0) +, m_chromaCbQpOffset (0) +, m_chromaCrQpOffset (0) +, m_numRefIdxL0DefaultActive (1) +, m_numRefIdxL1DefaultActive (1) +, m_useCrossComponentPrediction (false) +, m_TransquantBypassEnableFlag (false) +, m_useTransformSkip (false) +, m_transformSkipLog2MaxSize (2) +, m_dependentSliceSegmentsEnabledFlag(false) +, m_tilesEnabledFlag (false) +, m_entropyCodingSyncEnabledFlag (false) +, m_loopFilterAcrossTilesEnabledFlag (true) +, m_uniformSpacingFlag (false) +, m_numTileColumnsMinus1 (0) +, m_numTileRowsMinus1 (0) +, m_numSubstreams (1) +, m_signHideFlag (0) +, m_cabacInitPresentFlag (false) +, m_encCABACTableIdx (I_SLICE) +, m_sliceHeaderExtensionPresentFlag (false) +, m_loopFilterAcrossSlicesEnabledFlag(false) +, m_listsModificationPresentFlag (0) +, m_numExtraSliceHeaderBits (0) +{ + m_scalingList = new TComScalingList; + for(Int ch=0; ch= 0; k--) + { + Int temp = getDeltaPOC(k); + if (deltaPOC < temp) + { + setDeltaPOC(k+1, temp); + setUsed(k+1, getUsed(k)); + setDeltaPOC(k, deltaPOC); + setUsed(k, used); + } + } + } + // flip the negative values to largest first + Int numNegPics = getNumberOfNegativePictures(); + for(Int j=0, k=numNegPics-1; j < numNegPics>>1; j++, k--) + { + Int deltaPOC = getDeltaPOC(j); + Bool used = getUsed(j); + setDeltaPOC(j, getDeltaPOC(k)); + setUsed(j, getUsed(k)); + setDeltaPOC(k, deltaPOC); + setUsed(k, used); + } +} + +/** Prints the deltaPOC and RefIdc (if available) values in the RPS. + * A "*" is added to the deltaPOC value if it is Used bu current. + * \returns Void + */ +Void TComReferencePictureSet::printDeltaPOC() +{ + printf("DeltaPOC = { "); + for(Int j=0; j < getNumberOfPictures(); j++) + { + printf("%d%s ", getDeltaPOC(j), (getUsed(j)==1)?"*":""); + } + if (getInterRPSPrediction()) + { + printf("}, RefIdc = { "); + for(Int j=0; j < getNumRefIdc(); j++) + { + printf("%d ", getRefIdc(j)); + } + } + printf("}\n"); +} + +TComRPSList::TComRPSList() +:m_referencePictureSets (NULL) +{ +} + +TComRPSList::~TComRPSList() +{ +} + +Void TComRPSList::create( Int numberOfReferencePictureSets) +{ + m_numberOfReferencePictureSets = numberOfReferencePictureSets; + m_referencePictureSets = new TComReferencePictureSet[numberOfReferencePictureSets]; +} + +Void TComRPSList::destroy() +{ + if (m_referencePictureSets) + { + delete [] m_referencePictureSets; + } + m_numberOfReferencePictureSets = 0; + m_referencePictureSets = NULL; +} + + + +TComReferencePictureSet* TComRPSList::getReferencePictureSet(Int referencePictureSetNum) +{ + return &m_referencePictureSets[referencePictureSetNum]; +} + +Int TComRPSList::getNumberOfReferencePictureSets() +{ + return m_numberOfReferencePictureSets; +} + +Void TComRPSList::setNumberOfReferencePictureSets(Int numberOfReferencePictureSets) +{ + m_numberOfReferencePictureSets = numberOfReferencePictureSets; +} + +TComRefPicListModification::TComRefPicListModification() +: m_bRefPicListModificationFlagL0 (false) +, m_bRefPicListModificationFlagL1 (false) +{ + ::memset( m_RefPicSetIdxL0, 0, sizeof(m_RefPicSetIdxL0) ); + ::memset( m_RefPicSetIdxL1, 0, sizeof(m_RefPicSetIdxL1) ); +} + +TComRefPicListModification::~TComRefPicListModification() +{ +} + +TComScalingList::TComScalingList() +{ + init(); +} + +TComScalingList::~TComScalingList() +{ + destroy(); +} + +/** set default quantization matrix to array +*/ +Void TComSlice::setDefaultScalingList() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId=0;listIdprocessDefaultMatrix(sizeId, listId); + } + } +} +/** check if use default quantization matrix + * \returns true if use default quantization matrix in all size +*/ +Bool TComSlice::checkDefaultScalingList() +{ + UInt defaultCounter=0; + + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId=0;listIdgetScalingListAddress(sizeId,listId), getScalingList()->getScalingListDefaultAddress(sizeId, listId),sizeof(Int)*min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId])) // check value of matrix + && ((sizeId < SCALING_LIST_16x16) || (getScalingList()->getScalingListDC(sizeId,listId) == 16))) // check DC value + { + defaultCounter++; + } + } + } + + return (defaultCounter == (SCALING_LIST_NUM * SCALING_LIST_SIZE_NUM )) ? false : true; +} + +/** get scaling matrix from RefMatrixID + * \param sizeId size index + * \param Index of input matrix + * \param Index of reference matrix + */ +Void TComScalingList::processRefMatrix( UInt sizeId, UInt listId , UInt refListId ) +{ + ::memcpy(getScalingListAddress(sizeId, listId),((listId == refListId)? getScalingListDefaultAddress(sizeId, refListId): getScalingListAddress(sizeId, refListId)),sizeof(Int)*min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId])); +} + +/** parse syntax infomation + * \param pchFile syntax infomation + * \returns false if successful + */ + +static Void outputScalingListHelp(std::ostream &os) +{ + os << "The scaling list file specifies all matrices and their DC values; none can be missing,\n" + "but their order is arbitrary.\n\n" + "The matrices are specified by:\n" + "\n" + " ,,,....\n\n" + " Line-feeds can be added arbitrarily between values, and the number of values needs to be\n" + " at least the number of entries for the matrix (superfluous entries are ignored).\n" + " The is text on the same line as the matrix that is not checked\n" + " except to ensure that the matrix name token is unique. It is recommended that it is ' ='\n" + " The values in the matrices are the absolute values (0-255), not the delta values as\n" + " exchanged between the encoder and decoder\n\n" + "The DC values (for matrix sizes larger than 8x8) are specified by:\n" + "_DC\n" + " \n"; + + os << "The permitted matrix names are:\n"; + for(UInt sizeIdc = 0; sizeIdc < SCALING_LIST_SIZE_NUM; sizeIdc++) + { + for(UInt listIdc = 0; listIdc < SCALING_LIST_NUM; listIdc++) + { + if ((sizeIdc!=SCALING_LIST_32x32) || (listIdc%(SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) == 0)) + { + os << " " << MatrixType[sizeIdc][listIdc] << '\n'; + } + } + } +} + +Void TComScalingList::outputScalingLists(std::ostream &os) const +{ + for(UInt sizeIdc = 0; sizeIdc < SCALING_LIST_SIZE_NUM; sizeIdc++) + { + const UInt size = min(8,4<<(sizeIdc)); + for(UInt listIdc = 0; listIdc < SCALING_LIST_NUM; listIdc++) + { + if ((sizeIdc!=SCALING_LIST_32x32) || (listIdc%(SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) == 0)) + { + const Int *src = getScalingListAddress(sizeIdc, listIdc); + os << (MatrixType[sizeIdc][listIdc]) << " =\n "; + for(UInt y=0; y SCALING_LIST_8x8) + { + os << MatrixType_DC[sizeIdc][listIdc] << " = \n " << std::setw(3) << getScalingListDC(sizeIdc, listIdc) << "\n"; + } + os << "\n"; + } + } + } +} + +Bool TComScalingList::xParseScalingList(Char* pchFile) +{ + static const Int LINE_SIZE=1024; + FILE *fp = NULL; + Char line[LINE_SIZE]; + + if (pchFile == NULL) + { + fprintf(stderr, "Error: no scaling list file specified. Help on scaling lists being output\n"); + outputScalingListHelp(std::cout); + std::cout << "\n\nExample scaling list file using default values:\n\n"; + outputScalingLists(std::cout); + exit (1); + return true; + } + else if ((fp = fopen(pchFile,"r")) == (FILE*)NULL) + { + fprintf(stderr, "Error: cannot open scaling list file %s for reading\n",pchFile); + return true; + } + + for(UInt sizeIdc = 0; sizeIdc < SCALING_LIST_SIZE_NUM; sizeIdc++) + { + const UInt size = min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeIdc]); + + for(UInt listIdc = 0; listIdc < SCALING_LIST_NUM; listIdc++) + { + Int * const src = getScalingListAddress(sizeIdc, listIdc); + + if ((sizeIdc==SCALING_LIST_32x32) && (listIdc%(SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) != 0)) // derive chroma32x32 from chroma16x16 + { + const Int *srcNextSmallerSize = getScalingListAddress(sizeIdc-1, listIdc); + for(UInt i=0; i SCALING_LIST_8x8) ? getScalingListDC(sizeIdc-1, listIdc) : src[0]); + } + else + { + { + fseek(fp, 0, SEEK_SET); + Bool bFound=false; + while ((!feof(fp)) && (!bFound)) + { + Char *ret = fgets(line, LINE_SIZE, fp); + Char *findNamePosition= ret==NULL ? NULL : strstr(line, MatrixType[sizeIdc][listIdc]); + // This could be a match against the DC string as well, so verify it isn't + if (findNamePosition!= NULL && (MatrixType_DC[sizeIdc][listIdc]==NULL || strstr(line, MatrixType_DC[sizeIdc][listIdc])==NULL)) + { + bFound=true; + } + } + if (!bFound) + { + fprintf(stderr, "Error: cannot find Matrix %s from scaling list file %s\n", MatrixType[sizeIdc][listIdc], pchFile); + return true; + } + } + for (UInt i=0; i255) + { + fprintf(stderr, "Error: QMatrix entry #%d of value %d for Matrix %s from scaling list file %s at file position %ld is out of range (0 to 255)\n", i, data, MatrixType[sizeIdc][listIdc], pchFile, ftell(fp)); + return true; + } + src[i] = data; + } + + //set DC value for default matrix check + setScalingListDC(sizeIdc,listIdc,src[0]); + + if(sizeIdc > SCALING_LIST_8x8) + { + { + fseek(fp, 0, SEEK_SET); + Bool bFound=false; + while ((!feof(fp)) && (!bFound)) + { + Char *ret = fgets(line, LINE_SIZE, fp); + Char *findNamePosition= ret==NULL ? NULL : strstr(line, MatrixType_DC[sizeIdc][listIdc]); + if (findNamePosition!= NULL) + { + // This won't be a match against the non-DC string. + bFound=true; + } + } + if (!bFound) + { + fprintf(stderr, "Error: cannot find DC Matrix %s from scaling list file %s\n", MatrixType_DC[sizeIdc][listIdc], pchFile); + return true; + } + } + Int data; + if (fscanf(fp, "%d,", &data)!=1) + { + fprintf(stderr, "Error: cannot read DC %s from scaling list file %s at file position %ld\n", MatrixType_DC[sizeIdc][listIdc], pchFile, ftell(fp)); + return true; + } + if (data<0 || data>255) + { + fprintf(stderr, "Error: DC value %d for Matrix %s from scaling list file %s at file position %ld is out of range (0 to 255)\n", data, MatrixType[sizeIdc][listIdc], pchFile, ftell(fp)); + return true; + } + //overwrite DC value when size of matrix is larger than 16x16 + setScalingListDC(sizeIdc,listIdc,data); + } + } + } + } +// std::cout << "\n\nRead scaling lists of:\n\n"; +// outputScalingLists(std::cout); + + fclose(fp); + return false; +} + +/** initialization process of quantization matrix array + */ +Void TComScalingList::init() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++) + { + m_scalingListCoef[sizeId][listId] = new Int [min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId])]; + } + } +} + +/** destroy quantization matrix array + */ +Void TComScalingList::destroy() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++) + { + if(m_scalingListCoef[sizeId][listId]) delete [] m_scalingListCoef[sizeId][listId]; + } + } +} + +/** get default address of quantization matrix + * \param sizeId size index + * \param listId list index + * \returns pointer of quantization matrix + */ +Int* TComScalingList::getScalingListDefaultAddress(UInt sizeId, UInt listId) +{ + Int *src = 0; + switch(sizeId) + { + case SCALING_LIST_4x4: + src = g_quantTSDefault4x4; + break; + case SCALING_LIST_8x8: + case SCALING_LIST_16x16: + case SCALING_LIST_32x32: + src = (listId < (SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) ) ? g_quantIntraDefault8x8 : g_quantInterDefault8x8; + break; + default: + assert(0); + src = NULL; + break; + } + return src; +} + +/** process of default matrix + * \param sizeId size index + * \param Index of input matrix + */ +Void TComScalingList::processDefaultMatrix(UInt sizeId, UInt listId) +{ + ::memcpy(getScalingListAddress(sizeId, listId),getScalingListDefaultAddress(sizeId,listId),sizeof(Int)*min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId])); + setScalingListDC(sizeId,listId,SCALING_LIST_DC); +} + +/** check DC value of matrix for default matrix signaling + */ +Void TComScalingList::checkDcOfMatrix() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++) + { + //check default matrix? + if(getScalingListDC(sizeId,listId) == 0) + { + processDefaultMatrix(sizeId, listId); + } + } + } +} + +ParameterSetManager::ParameterSetManager() +: m_vpsMap(MAX_NUM_VPS) +, m_spsMap(MAX_NUM_SPS) +, m_ppsMap(MAX_NUM_PPS) +, m_activeVPSId(-1) +, m_activeSPSId(-1) +, m_activePPSId(-1) +{ +} + + +ParameterSetManager::~ParameterSetManager() +{ +} + +//! activate a SPS from a active parameter sets SEI message +//! \returns true, if activation is successful +Bool ParameterSetManager::activateSPSWithSEI(Int spsId) +{ + TComSPS *sps = m_spsMap.getPS(spsId); + if (sps) + { + Int vpsId = sps->getVPSId(); + if (m_vpsMap.getPS(vpsId)) + { + m_activeVPSId = vpsId; + m_activeSPSId = spsId; + return true; + } + else + { + printf("Warning: tried to activate SPS using an Active parameter sets SEI message. Referenced VPS does not exist."); + } + } + else + { + printf("Warning: tried to activate non-existing SPS using an Active parameter sets SEI message."); + } + return false; +} + +//! activate a PPS and depending on isIDR parameter also SPS and VPS +//! \returns true, if activation is successful +Bool ParameterSetManager::activatePPS(Int ppsId, Bool isIRAP) +{ + TComPPS *pps = m_ppsMap.getPS(ppsId); + if (pps) + { + Int spsId = pps->getSPSId(); + if (!isIRAP && (spsId != m_activeSPSId)) + { + printf("Warning: tried to activate PPS referring to a inactive SPS at non-IDR."); + return false; + } + TComSPS *sps = m_spsMap.getPS(spsId); + if (sps) + { + Int vpsId = sps->getVPSId(); + if (!isIRAP && (vpsId != m_activeVPSId)) + { + printf("Warning: tried to activate PPS referring to a inactive VPS at non-IDR."); + return false; + } + if (m_vpsMap.getPS(vpsId)) + { + m_activePPSId = ppsId; + m_activeVPSId = vpsId; + m_activeSPSId = spsId; + return true; + } + else + { + printf("Warning: tried to activate PPS that refers to a non-existing VPS."); + } + } + else + { + printf("Warning: tried to activate a PPS that refers to a non-existing SPS."); + } + } + else + { + printf("Warning: tried to activate non-existing PPS."); + } + return false; +} + +ProfileTierLevel::ProfileTierLevel() + : m_profileSpace (0) + , m_tierFlag (Level::MAIN) + , m_profileIdc (Profile::NONE) + , m_levelIdc (Level::NONE) + , m_progressiveSourceFlag (false) + , m_interlacedSourceFlag (false) + , m_nonPackedConstraintFlag(false) + , m_frameOnlyConstraintFlag(false) +{ + ::memset(m_profileCompatibilityFlag, 0, sizeof(m_profileCompatibilityFlag)); +} + +TComPTL::TComPTL() +{ + ::memset(m_subLayerProfilePresentFlag, 0, sizeof(m_subLayerProfilePresentFlag)); + ::memset(m_subLayerLevelPresentFlag, 0, sizeof(m_subLayerLevelPresentFlag )); +} + + +//! \} diff --git a/jctvc/TLibCommon/TComSlice.h b/jctvc/TLibCommon/TComSlice.h new file mode 100644 index 0000000..abed1bc --- /dev/null +++ b/jctvc/TLibCommon/TComSlice.h @@ -0,0 +1,1595 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComSlice.h + \brief slice header and SPS class (header) +*/ + +#ifndef __TCOMSLICE__ +#define __TCOMSLICE__ + +#include +#include +#include +#include "CommonDef.h" +#include "TComRom.h" +#include "TComList.h" +#include "TComChromaFormat.h" + +//! \ingroup TLibCommon +//! \{ + +class TComPic; +class TComTrQuant; +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +static const UInt REF_PIC_LIST_NUM_IDX=32; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// Reference Picture Set class +class TComReferencePictureSet +{ +private: + Int m_numberOfPictures; + Int m_numberOfNegativePictures; + Int m_numberOfPositivePictures; + Int m_numberOfLongtermPictures; + Int m_deltaPOC[MAX_NUM_REF_PICS]; + Int m_POC[MAX_NUM_REF_PICS]; + Bool m_used[MAX_NUM_REF_PICS]; + Bool m_interRPSPrediction; + Int m_deltaRIdxMinus1; + Int m_deltaRPS; + Int m_numRefIdc; + Int m_refIdc[MAX_NUM_REF_PICS+1]; + Bool m_bCheckLTMSB[MAX_NUM_REF_PICS]; + Int m_pocLSBLT[MAX_NUM_REF_PICS]; + Int m_deltaPOCMSBCycleLT[MAX_NUM_REF_PICS]; + Bool m_deltaPocMSBPresentFlag[MAX_NUM_REF_PICS]; + +public: + TComReferencePictureSet(); + virtual ~TComReferencePictureSet(); + Int getPocLSBLT(Int i) { return m_pocLSBLT[i]; } + Void setPocLSBLT(Int i, Int x) { m_pocLSBLT[i] = x; } + Int getDeltaPocMSBCycleLT(Int i) { return m_deltaPOCMSBCycleLT[i]; } + Void setDeltaPocMSBCycleLT(Int i, Int x) { m_deltaPOCMSBCycleLT[i] = x; } + Bool getDeltaPocMSBPresentFlag(Int i) { return m_deltaPocMSBPresentFlag[i]; } + Void setDeltaPocMSBPresentFlag(Int i, Bool x) { m_deltaPocMSBPresentFlag[i] = x; } + Void setUsed(Int bufferNum, Bool used); + Void setDeltaPOC(Int bufferNum, Int deltaPOC); + Void setPOC(Int bufferNum, Int deltaPOC); + Void setNumberOfPictures(Int numberOfPictures); + Void setCheckLTMSBPresent(Int bufferNum, Bool b ); + Bool getCheckLTMSBPresent(Int bufferNum); + + Int getUsed(Int bufferNum); + Int getDeltaPOC(Int bufferNum); + Int getPOC(Int bufferNum); + Int getNumberOfPictures(); + + Void setNumberOfNegativePictures(Int number) { m_numberOfNegativePictures = number; } + Int getNumberOfNegativePictures() { return m_numberOfNegativePictures; } + Void setNumberOfPositivePictures(Int number) { m_numberOfPositivePictures = number; } + Int getNumberOfPositivePictures() { return m_numberOfPositivePictures; } + Void setNumberOfLongtermPictures(Int number) { m_numberOfLongtermPictures = number; } + Int getNumberOfLongtermPictures() { return m_numberOfLongtermPictures; } + + Void setInterRPSPrediction(Bool flag) { m_interRPSPrediction = flag; } + Bool getInterRPSPrediction() { return m_interRPSPrediction; } + Void setDeltaRIdxMinus1(Int x) { m_deltaRIdxMinus1 = x; } + Int getDeltaRIdxMinus1() { return m_deltaRIdxMinus1; } + Void setDeltaRPS(Int x) { m_deltaRPS = x; } + Int getDeltaRPS() { return m_deltaRPS; } + Void setNumRefIdc(Int x) { m_numRefIdc = x; } + Int getNumRefIdc() { return m_numRefIdc; } + + Void setRefIdc(Int bufferNum, Int refIdc); + Int getRefIdc(Int bufferNum); + + Void sortDeltaPOC(); + Void printDeltaPOC(); +}; + +/// Reference Picture Set set class +class TComRPSList +{ +private: + Int m_numberOfReferencePictureSets; + TComReferencePictureSet* m_referencePictureSets; + +public: + TComRPSList(); + virtual ~TComRPSList(); + + Void create (Int numberOfEntries); + Void destroy (); + + + TComReferencePictureSet* getReferencePictureSet(Int referencePictureSetNum); + Int getNumberOfReferencePictureSets(); + Void setNumberOfReferencePictureSets(Int numberOfReferencePictureSets); +}; + +/// SCALING_LIST class +class TComScalingList +{ +public: + TComScalingList(); + virtual ~TComScalingList(); + Void setScalingListPresentFlag (Bool b) { m_scalingListPresentFlag = b; } + Bool getScalingListPresentFlag () { return m_scalingListPresentFlag; } + Int* getScalingListAddress (UInt sizeId, UInt listId) { return m_scalingListCoef[sizeId][listId]; } //!< get matrix coefficient + const Int* getScalingListAddress (UInt sizeId, UInt listId) const { return m_scalingListCoef[sizeId][listId]; } //!< get matrix coefficient + Bool checkPredMode (UInt sizeId, UInt listId); + Void setRefMatrixId (UInt sizeId, UInt listId, UInt u) { m_refMatrixId[sizeId][listId] = u; } //!< set reference matrix ID + UInt getRefMatrixId (UInt sizeId, UInt listId) { return m_refMatrixId[sizeId][listId]; } //!< get reference matrix ID + Int* getScalingListDefaultAddress (UInt sizeId, UInt listId); //!< get default matrix coefficient + Void processDefaultMatrix (UInt sizeId, UInt listId); + Void setScalingListDC (UInt sizeId, UInt listId, UInt u) { m_scalingListDC[sizeId][listId] = u; } //!< set DC value + + Int getScalingListDC (UInt sizeId, UInt listId) const { return m_scalingListDC[sizeId][listId]; } //!< get DC value + Void checkDcOfMatrix (); + Void processRefMatrix (UInt sizeId, UInt listId , UInt refListId ); + Bool xParseScalingList (Char* pchFile); + +private: + Void init (); + Void destroy (); + Void outputScalingLists(std::ostream &os) const; + Int m_scalingListDC [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; //!< the DC value of the matrix coefficient for 16x16 + Bool m_useDefaultScalingMatrixFlag [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; //!< UseDefaultScalingMatrixFlag + UInt m_refMatrixId [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; //!< RefMatrixID + Bool m_scalingListPresentFlag; //!< flag for using default matrix + UInt m_predMatrixId [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; //!< reference list index + Int *m_scalingListCoef [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM]; //!< quantization matrix +}; + +class ProfileTierLevel +{ + Int m_profileSpace; + Level::Tier m_tierFlag; + Profile::Name m_profileIdc; + Bool m_profileCompatibilityFlag[32]; + Level::Name m_levelIdc; + + Bool m_progressiveSourceFlag; + Bool m_interlacedSourceFlag; + Bool m_nonPackedConstraintFlag; + Bool m_frameOnlyConstraintFlag; + UInt m_bitDepthConstraintValue; + ChromaFormat m_chromaFormatConstraintValue; + Bool m_intraConstraintFlag; + Bool m_lowerBitRateConstraintFlag; + +public: + ProfileTierLevel(); + + Int getProfileSpace() const { return m_profileSpace; } + Void setProfileSpace(Int x) { m_profileSpace = x; } + + Level::Tier getTierFlag() const { return m_tierFlag; } + Void setTierFlag(Level::Tier x) { m_tierFlag = x; } + + Profile::Name getProfileIdc() const { return m_profileIdc; } + Void setProfileIdc(Profile::Name x) { m_profileIdc = x; } + + Bool getProfileCompatibilityFlag(Int i) const { return m_profileCompatibilityFlag[i]; } + Void setProfileCompatibilityFlag(Int i, Bool x) { m_profileCompatibilityFlag[i] = x; } + + Level::Name getLevelIdc() const { return m_levelIdc; } + Void setLevelIdc(Level::Name x) { m_levelIdc = x; } + + Bool getProgressiveSourceFlag() const { return m_progressiveSourceFlag; } + Void setProgressiveSourceFlag(Bool b) { m_progressiveSourceFlag = b; } + + Bool getInterlacedSourceFlag() const { return m_interlacedSourceFlag; } + Void setInterlacedSourceFlag(Bool b) { m_interlacedSourceFlag = b; } + + Bool getNonPackedConstraintFlag() const { return m_nonPackedConstraintFlag; } + Void setNonPackedConstraintFlag(Bool b) { m_nonPackedConstraintFlag = b; } + + Bool getFrameOnlyConstraintFlag() const { return m_frameOnlyConstraintFlag; } + Void setFrameOnlyConstraintFlag(Bool b) { m_frameOnlyConstraintFlag = b; } + + UInt getBitDepthConstraint() const { return m_bitDepthConstraintValue; } + Void setBitDepthConstraint(UInt bitDepth) { m_bitDepthConstraintValue=bitDepth; } + + ChromaFormat getChromaFormatConstraint() const { return m_chromaFormatConstraintValue; } + Void setChromaFormatConstraint(ChromaFormat fmt) { m_chromaFormatConstraintValue=fmt; } + + Bool getIntraConstraintFlag() const { return m_intraConstraintFlag; } + Void setIntraConstraintFlag(Bool b) { m_intraConstraintFlag = b; } + + Bool getLowerBitRateConstraintFlag() const { return m_lowerBitRateConstraintFlag; } + Void setLowerBitRateConstraintFlag(Bool b) { m_lowerBitRateConstraintFlag = b; } +}; + + +class TComPTL +{ + ProfileTierLevel m_generalPTL; + ProfileTierLevel m_subLayerPTL [MAX_TLAYER-1]; // max. value of max_sub_layers_minus1 is MAX_TLAYER-1 (= 6) + Bool m_subLayerProfilePresentFlag [MAX_TLAYER-1]; + Bool m_subLayerLevelPresentFlag [MAX_TLAYER-1]; + +public: + TComPTL(); + Bool getSubLayerProfilePresentFlag(Int i) const { return m_subLayerProfilePresentFlag[i]; } + Void setSubLayerProfilePresentFlag(Int i, Bool x) { m_subLayerProfilePresentFlag[i] = x; } + + Bool getSubLayerLevelPresentFlag(Int i) const { return m_subLayerLevelPresentFlag[i]; } + Void setSubLayerLevelPresentFlag(Int i, Bool x) { m_subLayerLevelPresentFlag[i] = x; } + + ProfileTierLevel* getGeneralPTL() { return &m_generalPTL; } + ProfileTierLevel* getSubLayerPTL(Int i) { return &m_subLayerPTL[i]; } +}; + +/// VPS class + +struct HrdSubLayerInfo +{ + Bool fixedPicRateFlag; + Bool fixedPicRateWithinCvsFlag; + UInt picDurationInTcMinus1; + Bool lowDelayHrdFlag; + UInt cpbCntMinus1; + UInt bitRateValueMinus1[MAX_CPB_CNT][2]; + UInt cpbSizeValue [MAX_CPB_CNT][2]; + UInt ducpbSizeValue [MAX_CPB_CNT][2]; + UInt cbrFlag [MAX_CPB_CNT][2]; + UInt duBitRateValue [MAX_CPB_CNT][2]; +}; + +class TComHRD +{ +private: + Bool m_nalHrdParametersPresentFlag; + Bool m_vclHrdParametersPresentFlag; + Bool m_subPicCpbParamsPresentFlag; + UInt m_tickDivisorMinus2; + UInt m_duCpbRemovalDelayLengthMinus1; + Bool m_subPicCpbParamsInPicTimingSEIFlag; + UInt m_dpbOutputDelayDuLengthMinus1; + UInt m_bitRateScale; + UInt m_cpbSizeScale; + UInt m_ducpbSizeScale; + UInt m_initialCpbRemovalDelayLengthMinus1; + UInt m_cpbRemovalDelayLengthMinus1; + UInt m_dpbOutputDelayLengthMinus1; + UInt m_numDU; + HrdSubLayerInfo m_HRD[MAX_TLAYER]; + +public: + TComHRD() + :m_nalHrdParametersPresentFlag(0) + ,m_vclHrdParametersPresentFlag(0) + ,m_subPicCpbParamsPresentFlag(false) + ,m_tickDivisorMinus2(0) + ,m_duCpbRemovalDelayLengthMinus1(0) + ,m_subPicCpbParamsInPicTimingSEIFlag(false) + ,m_dpbOutputDelayDuLengthMinus1(0) + ,m_bitRateScale(0) + ,m_cpbSizeScale(0) + ,m_initialCpbRemovalDelayLengthMinus1(23) + ,m_cpbRemovalDelayLengthMinus1(23) + ,m_dpbOutputDelayLengthMinus1(23) + {} + + virtual ~TComHRD() {} + + Void setNalHrdParametersPresentFlag ( Bool flag ) { m_nalHrdParametersPresentFlag = flag; } + Bool getNalHrdParametersPresentFlag ( ) { return m_nalHrdParametersPresentFlag; } + + Void setVclHrdParametersPresentFlag ( Bool flag ) { m_vclHrdParametersPresentFlag = flag; } + Bool getVclHrdParametersPresentFlag ( ) { return m_vclHrdParametersPresentFlag; } + + Void setSubPicCpbParamsPresentFlag ( Bool flag ) { m_subPicCpbParamsPresentFlag = flag; } + Bool getSubPicCpbParamsPresentFlag ( ) { return m_subPicCpbParamsPresentFlag; } + + Void setTickDivisorMinus2 ( UInt value ) { m_tickDivisorMinus2 = value; } + UInt getTickDivisorMinus2 ( ) { return m_tickDivisorMinus2; } + + Void setDuCpbRemovalDelayLengthMinus1 ( UInt value ) { m_duCpbRemovalDelayLengthMinus1 = value; } + UInt getDuCpbRemovalDelayLengthMinus1 ( ) { return m_duCpbRemovalDelayLengthMinus1; } + + Void setSubPicCpbParamsInPicTimingSEIFlag ( Bool flag) { m_subPicCpbParamsInPicTimingSEIFlag = flag; } + Bool getSubPicCpbParamsInPicTimingSEIFlag () { return m_subPicCpbParamsInPicTimingSEIFlag; } + + Void setDpbOutputDelayDuLengthMinus1 (UInt value ) { m_dpbOutputDelayDuLengthMinus1 = value; } + UInt getDpbOutputDelayDuLengthMinus1 () { return m_dpbOutputDelayDuLengthMinus1; } + + Void setBitRateScale ( UInt value ) { m_bitRateScale = value; } + UInt getBitRateScale ( ) { return m_bitRateScale; } + + Void setCpbSizeScale ( UInt value ) { m_cpbSizeScale = value; } + UInt getCpbSizeScale ( ) { return m_cpbSizeScale; } + Void setDuCpbSizeScale ( UInt value ) { m_ducpbSizeScale = value; } + UInt getDuCpbSizeScale ( ) { return m_ducpbSizeScale; } + + Void setInitialCpbRemovalDelayLengthMinus1( UInt value ) { m_initialCpbRemovalDelayLengthMinus1 = value; } + UInt getInitialCpbRemovalDelayLengthMinus1( ) { return m_initialCpbRemovalDelayLengthMinus1; } + + Void setCpbRemovalDelayLengthMinus1 ( UInt value ) { m_cpbRemovalDelayLengthMinus1 = value; } + UInt getCpbRemovalDelayLengthMinus1 ( ) { return m_cpbRemovalDelayLengthMinus1; } + + Void setDpbOutputDelayLengthMinus1 ( UInt value ) { m_dpbOutputDelayLengthMinus1 = value; } + UInt getDpbOutputDelayLengthMinus1 ( ) { return m_dpbOutputDelayLengthMinus1; } + + Void setFixedPicRateFlag ( Int layer, Bool flag ) { m_HRD[layer].fixedPicRateFlag = flag; } + Bool getFixedPicRateFlag ( Int layer ) { return m_HRD[layer].fixedPicRateFlag; } + + Void setFixedPicRateWithinCvsFlag ( Int layer, Bool flag ) { m_HRD[layer].fixedPicRateWithinCvsFlag = flag; } + Bool getFixedPicRateWithinCvsFlag ( Int layer ) { return m_HRD[layer].fixedPicRateWithinCvsFlag; } + + Void setPicDurationInTcMinus1 ( Int layer, UInt value ) { m_HRD[layer].picDurationInTcMinus1 = value; } + UInt getPicDurationInTcMinus1 ( Int layer ) { return m_HRD[layer].picDurationInTcMinus1; } + + Void setLowDelayHrdFlag ( Int layer, Bool flag ) { m_HRD[layer].lowDelayHrdFlag = flag; } + Bool getLowDelayHrdFlag ( Int layer ) { return m_HRD[layer].lowDelayHrdFlag; } + + Void setCpbCntMinus1 ( Int layer, UInt value ) { m_HRD[layer].cpbCntMinus1 = value; } + UInt getCpbCntMinus1 ( Int layer ) { return m_HRD[layer].cpbCntMinus1; } + + Void setBitRateValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl, UInt value ) { m_HRD[layer].bitRateValueMinus1[cpbcnt][nalOrVcl] = value; } + UInt getBitRateValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl ) { return m_HRD[layer].bitRateValueMinus1[cpbcnt][nalOrVcl]; } + + Void setCpbSizeValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl, UInt value ) { m_HRD[layer].cpbSizeValue[cpbcnt][nalOrVcl] = value; } + UInt getCpbSizeValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl ) { return m_HRD[layer].cpbSizeValue[cpbcnt][nalOrVcl]; } + Void setDuCpbSizeValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl, UInt value ) { m_HRD[layer].ducpbSizeValue[cpbcnt][nalOrVcl] = value; } + UInt getDuCpbSizeValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl ) { return m_HRD[layer].ducpbSizeValue[cpbcnt][nalOrVcl]; } + Void setDuBitRateValueMinus1 ( Int layer, Int cpbcnt, Int nalOrVcl, UInt value ) { m_HRD[layer].duBitRateValue[cpbcnt][nalOrVcl] = value; } + UInt getDuBitRateValueMinus1 (Int layer, Int cpbcnt, Int nalOrVcl ) { return m_HRD[layer].duBitRateValue[cpbcnt][nalOrVcl]; } + Void setCbrFlag ( Int layer, Int cpbcnt, Int nalOrVcl, UInt value ) { m_HRD[layer].cbrFlag[cpbcnt][nalOrVcl] = value; } + Bool getCbrFlag ( Int layer, Int cpbcnt, Int nalOrVcl ) { return m_HRD[layer].cbrFlag[cpbcnt][nalOrVcl]; } + + Void setNumDU ( UInt value ) { m_numDU = value; } + UInt getNumDU ( ) { return m_numDU; } + Bool getCpbDpbDelaysPresentFlag() { return getNalHrdParametersPresentFlag() || getVclHrdParametersPresentFlag(); } +}; + +class TimingInfo +{ + Bool m_timingInfoPresentFlag; + UInt m_numUnitsInTick; + UInt m_timeScale; + Bool m_pocProportionalToTimingFlag; + Int m_numTicksPocDiffOneMinus1; +public: + TimingInfo() + : m_timingInfoPresentFlag(false) + , m_numUnitsInTick(1001) + , m_timeScale(60000) + , m_pocProportionalToTimingFlag(false) + , m_numTicksPocDiffOneMinus1(0) {} + + Void setTimingInfoPresentFlag ( Bool flag ) { m_timingInfoPresentFlag = flag; } + Bool getTimingInfoPresentFlag ( ) { return m_timingInfoPresentFlag; } + + Void setNumUnitsInTick ( UInt value ) { m_numUnitsInTick = value; } + UInt getNumUnitsInTick ( ) { return m_numUnitsInTick; } + + Void setTimeScale ( UInt value ) { m_timeScale = value; } + UInt getTimeScale ( ) { return m_timeScale; } + + Bool getPocProportionalToTimingFlag ( ) { return m_pocProportionalToTimingFlag; } + Void setPocProportionalToTimingFlag (Bool x ) { m_pocProportionalToTimingFlag = x; } + + Int getNumTicksPocDiffOneMinus1 ( ) { return m_numTicksPocDiffOneMinus1; } + Void setNumTicksPocDiffOneMinus1 (Int x ) { m_numTicksPocDiffOneMinus1 = x; } +}; + +struct ChromaQpAdj +{ + union + { + struct { + Int CbOffset; + Int CrOffset; + } comp; + Int offset[2]; /* two chroma components */ + } u; +}; + +class TComVPS +{ +private: + Int m_VPSId; + UInt m_uiMaxTLayers; + UInt m_uiMaxLayers; + Bool m_bTemporalIdNestingFlag; + + UInt m_numReorderPics[MAX_TLAYER]; + UInt m_uiMaxDecPicBuffering[MAX_TLAYER]; + UInt m_uiMaxLatencyIncrease[MAX_TLAYER]; // Really max latency increase plus 1 (value 0 expresses no limit) + + UInt m_numHrdParameters; + UInt m_maxNuhReservedZeroLayerId; + TComHRD* m_hrdParameters; + UInt* m_hrdOpSetIdx; + Bool* m_cprmsPresentFlag; + UInt m_numOpSets; + Bool m_layerIdIncludedFlag[MAX_VPS_OP_SETS_PLUS1][MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1]; + + TComPTL m_pcPTL; + TimingInfo m_timingInfo; + +public: + TComVPS(); + virtual ~TComVPS(); + + Void createHrdParamBuffer() + { + m_hrdParameters = new TComHRD[ getNumHrdParameters() ]; + m_hrdOpSetIdx = new UInt [ getNumHrdParameters() ]; + m_cprmsPresentFlag = new Bool [ getNumHrdParameters() ]; + } + + TComHRD* getHrdParameters ( UInt i ) { return &m_hrdParameters[ i ]; } + UInt getHrdOpSetIdx ( UInt i ) { return m_hrdOpSetIdx[ i ]; } + Void setHrdOpSetIdx ( UInt val, UInt i ) { m_hrdOpSetIdx[ i ] = val; } + Bool getCprmsPresentFlag ( UInt i ) { return m_cprmsPresentFlag[ i ]; } + Void setCprmsPresentFlag ( Bool val, UInt i ) { m_cprmsPresentFlag[ i ] = val; } + + Int getVPSId () { return m_VPSId; } + Void setVPSId (Int i) { m_VPSId = i; } + + UInt getMaxTLayers () { return m_uiMaxTLayers; } + Void setMaxTLayers (UInt t) { m_uiMaxTLayers = t; } + + UInt getMaxLayers () { return m_uiMaxLayers; } + Void setMaxLayers (UInt l) { m_uiMaxLayers = l; } + + Bool getTemporalNestingFlag () { return m_bTemporalIdNestingFlag; } + Void setTemporalNestingFlag (Bool t) { m_bTemporalIdNestingFlag = t; } + + Void setNumReorderPics(UInt v, UInt tLayer) { m_numReorderPics[tLayer] = v; } + UInt getNumReorderPics(UInt tLayer) { return m_numReorderPics[tLayer]; } + + Void setMaxDecPicBuffering(UInt v, UInt tLayer) { assert(tLayer < MAX_TLAYER); m_uiMaxDecPicBuffering[tLayer] = v; } + UInt getMaxDecPicBuffering(UInt tLayer) { return m_uiMaxDecPicBuffering[tLayer]; } + + Void setMaxLatencyIncrease(UInt v, UInt tLayer) { m_uiMaxLatencyIncrease[tLayer] = v; } + UInt getMaxLatencyIncrease(UInt tLayer) { return m_uiMaxLatencyIncrease[tLayer]; } + + UInt getNumHrdParameters() { return m_numHrdParameters; } + Void setNumHrdParameters(UInt v) { m_numHrdParameters = v; } + + UInt getMaxNuhReservedZeroLayerId() { return m_maxNuhReservedZeroLayerId; } + Void setMaxNuhReservedZeroLayerId(UInt v) { m_maxNuhReservedZeroLayerId = v; } + + UInt getMaxOpSets() { return m_numOpSets; } + Void setMaxOpSets(UInt v) { m_numOpSets = v; } + Bool getLayerIdIncludedFlag(UInt opsIdx, UInt id) { return m_layerIdIncludedFlag[opsIdx][id]; } + Void setLayerIdIncludedFlag(Bool v, UInt opsIdx, UInt id) { m_layerIdIncludedFlag[opsIdx][id] = v; } + + TComPTL* getPTL() { return &m_pcPTL; } + TimingInfo* getTimingInfo() { return &m_timingInfo; } +}; + +class Window +{ +private: + Bool m_enabledFlag; + Int m_winLeftOffset; + Int m_winRightOffset; + Int m_winTopOffset; + Int m_winBottomOffset; +public: + Window() + : m_enabledFlag (false) + , m_winLeftOffset (0) + , m_winRightOffset (0) + , m_winTopOffset (0) + , m_winBottomOffset (0) + { } + + Bool getWindowEnabledFlag() const { return m_enabledFlag; } + Void resetWindow() { m_enabledFlag = false; m_winLeftOffset = m_winRightOffset = m_winTopOffset = m_winBottomOffset = 0; } + Int getWindowLeftOffset() const { return m_enabledFlag ? m_winLeftOffset : 0; } + Void setWindowLeftOffset(Int val) { m_winLeftOffset = val; m_enabledFlag = true; } + Int getWindowRightOffset() const { return m_enabledFlag ? m_winRightOffset : 0; } + Void setWindowRightOffset(Int val) { m_winRightOffset = val; m_enabledFlag = true; } + Int getWindowTopOffset() const { return m_enabledFlag ? m_winTopOffset : 0; } + Void setWindowTopOffset(Int val) { m_winTopOffset = val; m_enabledFlag = true; } + Int getWindowBottomOffset() const { return m_enabledFlag ? m_winBottomOffset: 0; } + Void setWindowBottomOffset(Int val) { m_winBottomOffset = val; m_enabledFlag = true; } + + Void setWindow(Int offsetLeft, Int offsetLRight, Int offsetLTop, Int offsetLBottom) + { + m_enabledFlag = true; + m_winLeftOffset = offsetLeft; + m_winRightOffset = offsetLRight; + m_winTopOffset = offsetLTop; + m_winBottomOffset = offsetLBottom; + } +}; + + +class TComVUI +{ +private: + Bool m_aspectRatioInfoPresentFlag; + Int m_aspectRatioIdc; + Int m_sarWidth; + Int m_sarHeight; + Bool m_overscanInfoPresentFlag; + Bool m_overscanAppropriateFlag; + Bool m_videoSignalTypePresentFlag; + Int m_videoFormat; + Bool m_videoFullRangeFlag; + Bool m_colourDescriptionPresentFlag; + Int m_colourPrimaries; + Int m_transferCharacteristics; + Int m_matrixCoefficients; + Bool m_chromaLocInfoPresentFlag; + Int m_chromaSampleLocTypeTopField; + Int m_chromaSampleLocTypeBottomField; + Bool m_neutralChromaIndicationFlag; + Bool m_fieldSeqFlag; + Window m_defaultDisplayWindow; + Bool m_frameFieldInfoPresentFlag; + Bool m_hrdParametersPresentFlag; + Bool m_bitstreamRestrictionFlag; + Bool m_tilesFixedStructureFlag; + Bool m_motionVectorsOverPicBoundariesFlag; + Bool m_restrictedRefPicListsFlag; + Int m_minSpatialSegmentationIdc; + Int m_maxBytesPerPicDenom; + Int m_maxBitsPerMinCuDenom; + Int m_log2MaxMvLengthHorizontal; + Int m_log2MaxMvLengthVertical; + TComHRD m_hrdParameters; + TimingInfo m_timingInfo; + +public: + TComVUI() + :m_aspectRatioInfoPresentFlag(false) //TODO: This initialiser list contains magic numbers + ,m_aspectRatioIdc(0) + ,m_sarWidth(0) + ,m_sarHeight(0) + ,m_overscanInfoPresentFlag(false) + ,m_overscanAppropriateFlag(false) + ,m_videoSignalTypePresentFlag(false) + ,m_videoFormat(5) + ,m_videoFullRangeFlag(false) + ,m_colourDescriptionPresentFlag(false) + ,m_colourPrimaries(2) + ,m_transferCharacteristics(2) + ,m_matrixCoefficients(2) + ,m_chromaLocInfoPresentFlag(false) + ,m_chromaSampleLocTypeTopField(0) + ,m_chromaSampleLocTypeBottomField(0) + ,m_neutralChromaIndicationFlag(false) + ,m_fieldSeqFlag(false) + ,m_frameFieldInfoPresentFlag(false) + ,m_hrdParametersPresentFlag(false) + ,m_bitstreamRestrictionFlag(false) + ,m_tilesFixedStructureFlag(false) + ,m_motionVectorsOverPicBoundariesFlag(true) + ,m_restrictedRefPicListsFlag(1) + ,m_minSpatialSegmentationIdc(0) + ,m_maxBytesPerPicDenom(2) + ,m_maxBitsPerMinCuDenom(1) + ,m_log2MaxMvLengthHorizontal(15) + ,m_log2MaxMvLengthVertical(15) + {} + + virtual ~TComVUI() {} + + Bool getAspectRatioInfoPresentFlag() { return m_aspectRatioInfoPresentFlag; } + Void setAspectRatioInfoPresentFlag(Bool i) { m_aspectRatioInfoPresentFlag = i; } + + Int getAspectRatioIdc() { return m_aspectRatioIdc; } + Void setAspectRatioIdc(Int i) { m_aspectRatioIdc = i; } + + Int getSarWidth() { return m_sarWidth; } + Void setSarWidth(Int i) { m_sarWidth = i; } + + Int getSarHeight() { return m_sarHeight; } + Void setSarHeight(Int i) { m_sarHeight = i; } + + Bool getOverscanInfoPresentFlag() { return m_overscanInfoPresentFlag; } + Void setOverscanInfoPresentFlag(Bool i) { m_overscanInfoPresentFlag = i; } + + Bool getOverscanAppropriateFlag() { return m_overscanAppropriateFlag; } + Void setOverscanAppropriateFlag(Bool i) { m_overscanAppropriateFlag = i; } + + Bool getVideoSignalTypePresentFlag() { return m_videoSignalTypePresentFlag; } + Void setVideoSignalTypePresentFlag(Bool i) { m_videoSignalTypePresentFlag = i; } + + Int getVideoFormat() { return m_videoFormat; } + Void setVideoFormat(Int i) { m_videoFormat = i; } + + Bool getVideoFullRangeFlag() { return m_videoFullRangeFlag; } + Void setVideoFullRangeFlag(Bool i) { m_videoFullRangeFlag = i; } + + Bool getColourDescriptionPresentFlag() { return m_colourDescriptionPresentFlag; } + Void setColourDescriptionPresentFlag(Bool i) { m_colourDescriptionPresentFlag = i; } + + Int getColourPrimaries() { return m_colourPrimaries; } + Void setColourPrimaries(Int i) { m_colourPrimaries = i; } + + Int getTransferCharacteristics() { return m_transferCharacteristics; } + Void setTransferCharacteristics(Int i) { m_transferCharacteristics = i; } + + Int getMatrixCoefficients() { return m_matrixCoefficients; } + Void setMatrixCoefficients(Int i) { m_matrixCoefficients = i; } + + Bool getChromaLocInfoPresentFlag() { return m_chromaLocInfoPresentFlag; } + Void setChromaLocInfoPresentFlag(Bool i) { m_chromaLocInfoPresentFlag = i; } + + Int getChromaSampleLocTypeTopField() { return m_chromaSampleLocTypeTopField; } + Void setChromaSampleLocTypeTopField(Int i) { m_chromaSampleLocTypeTopField = i; } + + Int getChromaSampleLocTypeBottomField() { return m_chromaSampleLocTypeBottomField; } + Void setChromaSampleLocTypeBottomField(Int i) { m_chromaSampleLocTypeBottomField = i; } + + Bool getNeutralChromaIndicationFlag() { return m_neutralChromaIndicationFlag; } + Void setNeutralChromaIndicationFlag(Bool i) { m_neutralChromaIndicationFlag = i; } + + Bool getFieldSeqFlag() { return m_fieldSeqFlag; } + Void setFieldSeqFlag(Bool i) { m_fieldSeqFlag = i; } + + Bool getFrameFieldInfoPresentFlag() { return m_frameFieldInfoPresentFlag; } + Void setFrameFieldInfoPresentFlag(Bool i) { m_frameFieldInfoPresentFlag = i; } + + Window& getDefaultDisplayWindow() { return m_defaultDisplayWindow; } + Void setDefaultDisplayWindow(Window& defaultDisplayWindow ) { m_defaultDisplayWindow = defaultDisplayWindow; } + + Bool getHrdParametersPresentFlag() { return m_hrdParametersPresentFlag; } + Void setHrdParametersPresentFlag(Bool i) { m_hrdParametersPresentFlag = i; } + + Bool getBitstreamRestrictionFlag() { return m_bitstreamRestrictionFlag; } + Void setBitstreamRestrictionFlag(Bool i) { m_bitstreamRestrictionFlag = i; } + + Bool getTilesFixedStructureFlag() { return m_tilesFixedStructureFlag; } + Void setTilesFixedStructureFlag(Bool i) { m_tilesFixedStructureFlag = i; } + + Bool getMotionVectorsOverPicBoundariesFlag() { return m_motionVectorsOverPicBoundariesFlag; } + Void setMotionVectorsOverPicBoundariesFlag(Bool i) { m_motionVectorsOverPicBoundariesFlag = i; } + + Bool getRestrictedRefPicListsFlag() { return m_restrictedRefPicListsFlag; } + Void setRestrictedRefPicListsFlag(Bool b) { m_restrictedRefPicListsFlag = b; } + + Int getMinSpatialSegmentationIdc() { return m_minSpatialSegmentationIdc; } + Void setMinSpatialSegmentationIdc(Int i) { m_minSpatialSegmentationIdc = i; } + + Int getMaxBytesPerPicDenom() { return m_maxBytesPerPicDenom; } + Void setMaxBytesPerPicDenom(Int i) { m_maxBytesPerPicDenom = i; } + + Int getMaxBitsPerMinCuDenom() { return m_maxBitsPerMinCuDenom; } + Void setMaxBitsPerMinCuDenom(Int i) { m_maxBitsPerMinCuDenom = i; } + + Int getLog2MaxMvLengthHorizontal() { return m_log2MaxMvLengthHorizontal; } + Void setLog2MaxMvLengthHorizontal(Int i) { m_log2MaxMvLengthHorizontal = i; } + + Int getLog2MaxMvLengthVertical() { return m_log2MaxMvLengthVertical; } + Void setLog2MaxMvLengthVertical(Int i) { m_log2MaxMvLengthVertical = i; } + + TComHRD* getHrdParameters () { return &m_hrdParameters; } + + TimingInfo* getTimingInfo() { return &m_timingInfo; } +}; + +/// SPS class +class TComSPS +{ +private: + Int m_SPSId; + Int m_VPSId; + ChromaFormat m_chromaFormatIdc; + + UInt m_uiMaxTLayers; // maximum number of temporal layers + + // Structure + UInt m_picWidthInLumaSamples; + UInt m_picHeightInLumaSamples; + + Int m_log2MinCodingBlockSize; + Int m_log2DiffMaxMinCodingBlockSize; + UInt m_uiMaxCUWidth; + UInt m_uiMaxCUHeight; + UInt m_uiMaxCUDepth; + + Window m_conformanceWindow; + + TComRPSList m_RPSList; + Bool m_bLongTermRefsPresent; + Bool m_TMVPFlagsPresent; + Int m_numReorderPics[MAX_TLAYER]; + + // Tool list + UInt m_uiQuadtreeTULog2MaxSize; + UInt m_uiQuadtreeTULog2MinSize; + UInt m_uiQuadtreeTUMaxDepthInter; + UInt m_uiQuadtreeTUMaxDepthIntra; + Bool m_usePCM; + UInt m_pcmLog2MaxSize; + UInt m_uiPCMLog2MinSize; + Bool m_useAMP; + + // Parameter + Int m_uiBitDepth[MAX_NUM_CHANNEL_TYPE]; + Int m_qpBDOffset[MAX_NUM_CHANNEL_TYPE]; + Bool m_useExtendedPrecision; + Bool m_useHighPrecisionPredictionWeighting; + Bool m_useResidualRotation; + Bool m_useSingleSignificanceMapContext; + Bool m_useGolombRiceParameterAdaptation; + Bool m_alignCABACBeforeBypass; + Bool m_useResidualDPCM[NUMBER_OF_RDPCM_SIGNALLING_MODES]; + UInt m_uiPCMBitDepth[MAX_NUM_CHANNEL_TYPE]; + Bool m_bPCMFilterDisableFlag; + Bool m_disableIntraReferenceSmoothing; + + UInt m_uiBitsForPOC; + UInt m_numLongTermRefPicSPS; + UInt m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS]; + Bool m_usedByCurrPicLtSPSFlag[MAX_NUM_LONG_TERM_REF_PICS]; + // Max physical transform size + UInt m_uiMaxTrSize; + + Int m_iAMPAcc[MAX_CU_DEPTH]; + Bool m_bUseSAO; + + Bool m_bTemporalIdNestingFlag; // temporal_id_nesting_flag + + Bool m_scalingListEnabledFlag; + Bool m_scalingListPresentFlag; + TComScalingList* m_scalingList; //!< ScalingList class pointer + UInt m_uiMaxDecPicBuffering[MAX_TLAYER]; + UInt m_uiMaxLatencyIncrease[MAX_TLAYER]; // Really max latency increase plus 1 (value 0 expresses no limit) + + Bool m_useDF; + Bool m_useStrongIntraSmoothing; + + Bool m_vuiParametersPresentFlag; + TComVUI m_vuiParameters; + + static const Int m_winUnitX[MAX_CHROMA_FORMAT_IDC+1]; + static const Int m_winUnitY[MAX_CHROMA_FORMAT_IDC+1]; + TComPTL m_pcPTL; + +#if O0043_BEST_EFFORT_DECODING + UInt m_forceDecodeBitDepth; // 0 = do not force the decoder's bit depth, other = force the decoder's bit depth to this value (best effort decoding) +#endif + +public: + TComSPS(); + virtual ~TComSPS(); +#if O0043_BEST_EFFORT_DECODING + Void setForceDecodeBitDepth(UInt bitDepth) { m_forceDecodeBitDepth = bitDepth; } + UInt getForceDecodeBitDepth() const { return m_forceDecodeBitDepth; } +#endif + + Int getVPSId () { return m_VPSId; } + Void setVPSId (Int i) { m_VPSId = i; } + Int getSPSId () { return m_SPSId; } + Void setSPSId (Int i) { m_SPSId = i; } + ChromaFormat getChromaFormatIdc () { return m_chromaFormatIdc; } + Void setChromaFormatIdc (ChromaFormat i) { m_chromaFormatIdc = i; } + + static Int getWinUnitX (Int chromaFormatIdc) { assert (chromaFormatIdc >= 0 && chromaFormatIdc <= MAX_CHROMA_FORMAT_IDC); return m_winUnitX[chromaFormatIdc]; } + static Int getWinUnitY (Int chromaFormatIdc) { assert (chromaFormatIdc >= 0 && chromaFormatIdc <= MAX_CHROMA_FORMAT_IDC); return m_winUnitY[chromaFormatIdc]; } + + // structure + Void setPicWidthInLumaSamples ( UInt u ) { m_picWidthInLumaSamples = u; } + UInt getPicWidthInLumaSamples () { return m_picWidthInLumaSamples; } + Void setPicHeightInLumaSamples ( UInt u ) { m_picHeightInLumaSamples = u; } + UInt getPicHeightInLumaSamples () { return m_picHeightInLumaSamples; } + + Window& getConformanceWindow() { return m_conformanceWindow; } + Void setConformanceWindow(Window& conformanceWindow ) { m_conformanceWindow = conformanceWindow; } + + UInt getNumLongTermRefPicSPS() { return m_numLongTermRefPicSPS; } + Void setNumLongTermRefPicSPS(UInt val) { m_numLongTermRefPicSPS = val; } + + UInt getLtRefPicPocLsbSps(UInt index) { assert( index < MAX_NUM_LONG_TERM_REF_PICS ); return m_ltRefPicPocLsbSps[index]; } + Void setLtRefPicPocLsbSps(UInt index, UInt val) { assert( index < MAX_NUM_LONG_TERM_REF_PICS ); m_ltRefPicPocLsbSps[index] = val; } + + Bool getUsedByCurrPicLtSPSFlag(Int i) { assert( i < MAX_NUM_LONG_TERM_REF_PICS ); return m_usedByCurrPicLtSPSFlag[i];} + Void setUsedByCurrPicLtSPSFlag(Int i, Bool x) { assert( i < MAX_NUM_LONG_TERM_REF_PICS ); m_usedByCurrPicLtSPSFlag[i] = x;} + + Int getLog2MinCodingBlockSize() const { return m_log2MinCodingBlockSize; } + Void setLog2MinCodingBlockSize(Int val) { m_log2MinCodingBlockSize = val; } + Int getLog2DiffMaxMinCodingBlockSize() const { return m_log2DiffMaxMinCodingBlockSize; } + Void setLog2DiffMaxMinCodingBlockSize(Int val) { m_log2DiffMaxMinCodingBlockSize = val; } + + Void setMaxCUWidth ( UInt u ) { m_uiMaxCUWidth = u; } + UInt getMaxCUWidth () { return m_uiMaxCUWidth; } + Void setMaxCUHeight ( UInt u ) { m_uiMaxCUHeight = u; } + UInt getMaxCUHeight () { return m_uiMaxCUHeight; } + Void setMaxCUDepth ( UInt u ) { m_uiMaxCUDepth = u; } + UInt getMaxCUDepth () { return m_uiMaxCUDepth; } + Void setUsePCM ( Bool b ) { m_usePCM = b; } + Bool getUsePCM () { return m_usePCM; } + Void setPCMLog2MaxSize ( UInt u ) { m_pcmLog2MaxSize = u; } + UInt getPCMLog2MaxSize () { return m_pcmLog2MaxSize; } + Void setPCMLog2MinSize ( UInt u ) { m_uiPCMLog2MinSize = u; } + UInt getPCMLog2MinSize () { return m_uiPCMLog2MinSize; } + Void setBitsForPOC ( UInt u ) { m_uiBitsForPOC = u; } + UInt getBitsForPOC () { return m_uiBitsForPOC; } + Bool getUseAMP() { return m_useAMP; } + Void setUseAMP( Bool b ) { m_useAMP = b; } + Void setQuadtreeTULog2MaxSize( UInt u ) { m_uiQuadtreeTULog2MaxSize = u; } + UInt getQuadtreeTULog2MaxSize() { return m_uiQuadtreeTULog2MaxSize; } + Void setQuadtreeTULog2MinSize( UInt u ) { m_uiQuadtreeTULog2MinSize = u; } + UInt getQuadtreeTULog2MinSize() { return m_uiQuadtreeTULog2MinSize; } + Void setQuadtreeTUMaxDepthInter( UInt u ) { m_uiQuadtreeTUMaxDepthInter = u; } + Void setQuadtreeTUMaxDepthIntra( UInt u ) { m_uiQuadtreeTUMaxDepthIntra = u; } + UInt getQuadtreeTUMaxDepthInter() { return m_uiQuadtreeTUMaxDepthInter; } + UInt getQuadtreeTUMaxDepthIntra() { return m_uiQuadtreeTUMaxDepthIntra; } + Void setNumReorderPics(Int i, UInt tlayer) { m_numReorderPics[tlayer] = i; } + Int getNumReorderPics(UInt tlayer) { return m_numReorderPics[tlayer]; } + Void createRPSList( Int numRPS ); + TComRPSList* getRPSList() { return &m_RPSList; } + Bool getLongTermRefsPresent() { return m_bLongTermRefsPresent; } + Void setLongTermRefsPresent(Bool b) { m_bLongTermRefsPresent=b; } + Bool getTMVPFlagsPresent() { return m_TMVPFlagsPresent; } + Void setTMVPFlagsPresent(Bool b) { m_TMVPFlagsPresent=b; } + // physical transform + Void setMaxTrSize ( UInt u ) { m_uiMaxTrSize = u; } + UInt getMaxTrSize () { return m_uiMaxTrSize; } + + // AMP accuracy + Int getAMPAcc ( UInt uiDepth ) { return m_iAMPAcc[uiDepth]; } + Void setAMPAcc ( UInt uiDepth, Int iAccu ) { assert( uiDepth < g_uiMaxCUDepth); m_iAMPAcc[uiDepth] = iAccu; } + + // Bit-depth + Int getBitDepth (ChannelType type) { return m_uiBitDepth[type]; } + Void setBitDepth (ChannelType type, Int u ) { m_uiBitDepth[type] = u; } + Int getDifferentialLumaChromaBitDepth() const { return Int(m_uiBitDepth[CHANNEL_TYPE_LUMA]) - Int(m_uiBitDepth[CHANNEL_TYPE_CHROMA]); } + Int getQpBDOffset (ChannelType type) const { return m_qpBDOffset[type]; } + Void setQpBDOffset (ChannelType type, Int i) { m_qpBDOffset[type] = i; } + Bool getUseExtendedPrecision() const { return m_useExtendedPrecision; } + Void setUseExtendedPrecision(Bool value) { m_useExtendedPrecision = value; } + Bool getUseHighPrecisionPredictionWeighting() const { return m_useHighPrecisionPredictionWeighting; } + Void setUseHighPrecisionPredictionWeighting(Bool value) { m_useHighPrecisionPredictionWeighting = value; } + + Void setUseSAO (Bool bVal) {m_bUseSAO = bVal;} + Bool getUseSAO () {return m_bUseSAO;} + + Bool getUseResidualRotation () const { return m_useResidualRotation; } + Void setUseResidualRotation (const Bool value) { m_useResidualRotation = value; } + + Bool getUseSingleSignificanceMapContext() const { return m_useSingleSignificanceMapContext; } + Void setUseSingleSignificanceMapContext(const Bool value) { m_useSingleSignificanceMapContext = value; } + + Bool getUseGolombRiceParameterAdaptation() const { return m_useGolombRiceParameterAdaptation; } + Void setUseGolombRiceParameterAdaptation(const Bool value) { m_useGolombRiceParameterAdaptation = value; } + + Bool getAlignCABACBeforeBypass () const { return m_alignCABACBeforeBypass; } + Void setAlignCABACBeforeBypass (const Bool value) { m_alignCABACBeforeBypass = value; } + + Bool getUseResidualDPCM (const RDPCMSignallingMode signallingMode) const { return m_useResidualDPCM[signallingMode]; } + Void setUseResidualDPCM (const RDPCMSignallingMode signallingMode, const Bool value) { m_useResidualDPCM[signallingMode] = value; } + + UInt getMaxTLayers() { return m_uiMaxTLayers; } + Void setMaxTLayers( UInt uiMaxTLayers ) { assert( uiMaxTLayers <= MAX_TLAYER ); m_uiMaxTLayers = uiMaxTLayers; } + + Bool getTemporalIdNestingFlag() { return m_bTemporalIdNestingFlag; } + Void setTemporalIdNestingFlag( Bool bValue ) { m_bTemporalIdNestingFlag = bValue; } + UInt getPCMBitDepth (ChannelType type) const { return m_uiPCMBitDepth[type]; } + Void setPCMBitDepth (ChannelType type, UInt u) { m_uiPCMBitDepth[type] = u; } + Void setPCMFilterDisableFlag ( Bool bValue ) { m_bPCMFilterDisableFlag = bValue; } + Bool getPCMFilterDisableFlag () { return m_bPCMFilterDisableFlag; } + Void setDisableIntraReferenceSmoothing (Bool bValue) { m_disableIntraReferenceSmoothing=bValue; } + Bool getDisableIntraReferenceSmoothing () const { return m_disableIntraReferenceSmoothing; } + + Bool getScalingListFlag () { return m_scalingListEnabledFlag; } + Void setScalingListFlag ( Bool b ) { m_scalingListEnabledFlag = b; } + Bool getScalingListPresentFlag() { return m_scalingListPresentFlag; } + Void setScalingListPresentFlag( Bool b ) { m_scalingListPresentFlag = b; } + Void setScalingList ( TComScalingList *scalingList); + TComScalingList* getScalingList () { return m_scalingList; } //!< get ScalingList class pointer in SPS + UInt getMaxDecPicBuffering (UInt tlayer) { return m_uiMaxDecPicBuffering[tlayer]; } + Void setMaxDecPicBuffering ( UInt ui, UInt tlayer ) { assert(tlayer < MAX_TLAYER); m_uiMaxDecPicBuffering[tlayer] = ui; } + UInt getMaxLatencyIncrease (UInt tlayer) { return m_uiMaxLatencyIncrease[tlayer]; } + Void setMaxLatencyIncrease ( UInt ui , UInt tlayer) { m_uiMaxLatencyIncrease[tlayer] = ui; } + + Void setUseStrongIntraSmoothing (Bool bVal) {m_useStrongIntraSmoothing = bVal;} + Bool getUseStrongIntraSmoothing () {return m_useStrongIntraSmoothing;} + + Bool getVuiParametersPresentFlag() { return m_vuiParametersPresentFlag; } + Void setVuiParametersPresentFlag(Bool b) { m_vuiParametersPresentFlag = b; } + TComVUI* getVuiParameters() { return &m_vuiParameters; } + Void setHrdParameters( UInt frameRate, UInt numDU, UInt bitRate, Bool randomAccess ); + + TComPTL* getPTL() { return &m_pcPTL; } +}; + +/// Reference Picture Lists class + +class TComRefPicListModification +{ +private: + UInt m_bRefPicListModificationFlagL0; + UInt m_bRefPicListModificationFlagL1; + UInt m_RefPicSetIdxL0[REF_PIC_LIST_NUM_IDX]; + UInt m_RefPicSetIdxL1[REF_PIC_LIST_NUM_IDX]; + +public: + TComRefPicListModification(); + virtual ~TComRefPicListModification(); + + Void create (); + Void destroy (); + + Bool getRefPicListModificationFlagL0() { return m_bRefPicListModificationFlagL0; } + Void setRefPicListModificationFlagL0(Bool flag) { m_bRefPicListModificationFlagL0 = flag; } + Bool getRefPicListModificationFlagL1() { return m_bRefPicListModificationFlagL1; } + Void setRefPicListModificationFlagL1(Bool flag) { m_bRefPicListModificationFlagL1 = flag; } + Void setRefPicSetIdxL0(UInt idx, UInt refPicSetIdx) { assert(idx m_tileColumnWidth; + std::vector m_tileRowHeight; + + Int m_numSubstreams; + + Int m_signHideFlag; + + Bool m_cabacInitPresentFlag; + UInt m_encCABACTableIdx; // Used to transmit table selection across slices + + Bool m_sliceHeaderExtensionPresentFlag; + Bool m_loopFilterAcrossSlicesEnabledFlag; + Bool m_deblockingFilterControlPresentFlag; + Bool m_deblockingFilterOverrideEnabledFlag; + Bool m_picDisableDeblockingFilterFlag; + Int m_deblockingFilterBetaOffsetDiv2; //< beta offset for deblocking filter + Int m_deblockingFilterTcOffsetDiv2; //< tc offset for deblocking filter + Bool m_scalingListPresentFlag; + TComScalingList* m_scalingList; //!< ScalingList class pointer + Bool m_listsModificationPresentFlag; + UInt m_log2ParallelMergeLevelMinus2; + Int m_numExtraSliceHeaderBits; + +public: + TComPPS(); + virtual ~TComPPS(); + + Int getPPSId () { return m_PPSId; } + Void setPPSId (Int i) { m_PPSId = i; } + Int getSPSId () { return m_SPSId; } + Void setSPSId (Int i) { m_SPSId = i; } + + Int getPicInitQPMinus26 () { return m_picInitQPMinus26; } + Void setPicInitQPMinus26 ( Int i ) { m_picInitQPMinus26 = i; } + Bool getUseDQP () { return m_useDQP; } + Void setUseDQP ( Bool b ) { m_useDQP = b; } + Bool getConstrainedIntraPred () { return m_bConstrainedIntraPred; } + Void setConstrainedIntraPred ( Bool b ) { m_bConstrainedIntraPred = b; } + Bool getSliceChromaQpFlag () { return m_bSliceChromaQpFlag; } + Void setSliceChromaQpFlag ( Bool b ) { m_bSliceChromaQpFlag = b; } + + Void setSPS ( TComSPS* pcSPS ) { m_pcSPS = pcSPS; } + TComSPS* getSPS () { return m_pcSPS; } + Void setMaxCuDQPDepth ( UInt u ) { m_uiMaxCuDQPDepth = u; } + UInt getMaxCuDQPDepth () { return m_uiMaxCuDQPDepth;} + Void setMinCuDQPSize ( UInt u ) { m_uiMinCuDQPSize = u; } + UInt getMinCuDQPSize () { return m_uiMinCuDQPSize; } + + Void setQpOffset(ComponentID compID, Int i ) { if (compID==COMPONENT_Cb) m_chromaCbQpOffset = i; else if (compID==COMPONENT_Cr) m_chromaCrQpOffset = i; else assert(0); } + Int getQpOffset(ComponentID compID) const { return (compID==COMPONENT_Y) ? 0 : (compID==COMPONENT_Cb ? m_chromaCbQpOffset : m_chromaCrQpOffset ); } + + Void setMaxCuChromaQpAdjDepth ( UInt u ) { m_MaxCuChromaQpAdjDepth = u; } + UInt getMaxCuChromaQpAdjDepth () { return m_MaxCuChromaQpAdjDepth; } + Void setMinCuChromaQpAdjSize ( UInt u ) { m_MinCuChromaQpAdjSize = u; } + UInt getMinCuChromaQpAdjSize () { return m_MinCuChromaQpAdjSize; } + Void clearChromaQpAdjTable() { m_ChromaQpAdjTableSize = 0; } + Int getChromaQpAdjTableSize() { return m_ChromaQpAdjTableSize; } + const ChromaQpAdj& getChromaQpAdjTableAt( Int idx ) const { return m_ChromaQpAdjTable[idx]; } + Void setChromaQpAdjTableAt( Int idx, Int cbOffset, Int crOffset ) + { + m_ChromaQpAdjTable[idx].u.comp.CbOffset = cbOffset; + m_ChromaQpAdjTable[idx].u.comp.CrOffset = crOffset; + m_ChromaQpAdjTableSize = max(m_ChromaQpAdjTableSize, idx); + } + + Void setNumRefIdxL0DefaultActive(UInt ui) { m_numRefIdxL0DefaultActive=ui; } + UInt getNumRefIdxL0DefaultActive() { return m_numRefIdxL0DefaultActive; } + Void setNumRefIdxL1DefaultActive(UInt ui) { m_numRefIdxL1DefaultActive=ui; } + UInt getNumRefIdxL1DefaultActive() { return m_numRefIdxL1DefaultActive; } + + Bool getUseWP () { return m_bUseWeightPred; } + Bool getWPBiPred () { return m_useWeightedBiPred; } + Void setUseWP ( Bool b ) { m_bUseWeightPred = b; } + Void setWPBiPred ( Bool b ) { m_useWeightedBiPred = b; } + + Bool getUseCrossComponentPrediction() const { return m_useCrossComponentPrediction; } + Void setUseCrossComponentPrediction(Bool value) { m_useCrossComponentPrediction = value; } + + UInt getSaoOffsetBitShift(ChannelType type) const { return m_saoOffsetBitShift[type]; } + Void setSaoOffsetBitShift(ChannelType type, UInt uiBitShift) { m_saoOffsetBitShift[type] = uiBitShift; } + + Void setOutputFlagPresentFlag( Bool b ) { m_OutputFlagPresentFlag = b; } + Bool getOutputFlagPresentFlag() { return m_OutputFlagPresentFlag; } + Void setTransquantBypassEnableFlag( Bool b ) { m_TransquantBypassEnableFlag = b; } + Bool getTransquantBypassEnableFlag() { return m_TransquantBypassEnableFlag; } + + Bool getUseTransformSkip () { return m_useTransformSkip; } + Void setUseTransformSkip ( Bool b ) { m_useTransformSkip = b; } + UInt getTransformSkipLog2MaxSize () { return m_transformSkipLog2MaxSize; } + Void setTransformSkipLog2MaxSize ( UInt u ) { m_transformSkipLog2MaxSize = u; } + + Void setLoopFilterAcrossTilesEnabledFlag (Bool b) { m_loopFilterAcrossTilesEnabledFlag = b; } + Bool getLoopFilterAcrossTilesEnabledFlag () { return m_loopFilterAcrossTilesEnabledFlag; } + Bool getDependentSliceSegmentsEnabledFlag() const { return m_dependentSliceSegmentsEnabledFlag; } + Void setDependentSliceSegmentsEnabledFlag(Bool val) { m_dependentSliceSegmentsEnabledFlag = val; } + Bool getEntropyCodingSyncEnabledFlag() const { return m_entropyCodingSyncEnabledFlag; } + Void setEntropyCodingSyncEnabledFlag(Bool val) { m_entropyCodingSyncEnabledFlag = val; } + + Void setTilesEnabledFlag (Bool val) { m_tilesEnabledFlag = val; } + Bool getTilesEnabledFlag () const { return m_tilesEnabledFlag; } + Void setTileUniformSpacingFlag (Bool b) { m_uniformSpacingFlag = b; } + Bool getTileUniformSpacingFlag () const { return m_uniformSpacingFlag; } + Void setNumTileColumnsMinus1 (Int i) { m_numTileColumnsMinus1 = i; } + Int getNumTileColumnsMinus1 () const { return m_numTileColumnsMinus1; } + Void setTileColumnWidth (const std::vector& columnWidth ) { m_tileColumnWidth = columnWidth; } + UInt getTileColumnWidth (UInt columnIdx) const { return m_tileColumnWidth[columnIdx]; } + Void setNumTileRowsMinus1 (Int i) { m_numTileRowsMinus1 = i; } + Int getNumTileRowsMinus1 () const { return m_numTileRowsMinus1; } + Void setTileRowHeight (const std::vector& rowHeight) { m_tileRowHeight = rowHeight; } + UInt getTileRowHeight (UInt rowIdx) const { return m_tileRowHeight[rowIdx]; } + + Void setNumSubstreams (Int numSubstreams) { m_numSubstreams = numSubstreams; } + Int getNumSubstreams () { return m_numSubstreams; } + + Void setSignHideFlag( Int signHideFlag ) { m_signHideFlag = signHideFlag; } + Int getSignHideFlag() { return m_signHideFlag; } + + Void setCabacInitPresentFlag( Bool flag ) { m_cabacInitPresentFlag = flag; } + Void setEncCABACTableIdx( Int idx ) { m_encCABACTableIdx = idx; } + Bool getCabacInitPresentFlag() { return m_cabacInitPresentFlag; } + UInt getEncCABACTableIdx() { return m_encCABACTableIdx; } + Void setDeblockingFilterControlPresentFlag( Bool val ) { m_deblockingFilterControlPresentFlag = val; } + Bool getDeblockingFilterControlPresentFlag() { return m_deblockingFilterControlPresentFlag; } + Void setDeblockingFilterOverrideEnabledFlag( Bool val ) { m_deblockingFilterOverrideEnabledFlag = val; } + Bool getDeblockingFilterOverrideEnabledFlag() { return m_deblockingFilterOverrideEnabledFlag; } + Void setPicDisableDeblockingFilterFlag(Bool val) { m_picDisableDeblockingFilterFlag = val; } //!< set offset for deblocking filter disabled + Bool getPicDisableDeblockingFilterFlag() { return m_picDisableDeblockingFilterFlag; } //!< get offset for deblocking filter disabled + Void setDeblockingFilterBetaOffsetDiv2(Int val) { m_deblockingFilterBetaOffsetDiv2 = val; } //!< set beta offset for deblocking filter + Int getDeblockingFilterBetaOffsetDiv2() { return m_deblockingFilterBetaOffsetDiv2; } //!< get beta offset for deblocking filter + Void setDeblockingFilterTcOffsetDiv2(Int val) { m_deblockingFilterTcOffsetDiv2 = val; } //!< set tc offset for deblocking filter + Int getDeblockingFilterTcOffsetDiv2() { return m_deblockingFilterTcOffsetDiv2; } //!< get tc offset for deblocking filter + Bool getScalingListPresentFlag() { return m_scalingListPresentFlag; } + Void setScalingListPresentFlag( Bool b ) { m_scalingListPresentFlag = b; } + Void setScalingList ( TComScalingList *scalingList); + TComScalingList* getScalingList () { return m_scalingList; } //!< get ScalingList class pointer in PPS + Bool getListsModificationPresentFlag () { return m_listsModificationPresentFlag; } + Void setListsModificationPresentFlag ( Bool b ) { m_listsModificationPresentFlag = b; } + UInt getLog2ParallelMergeLevelMinus2 () { return m_log2ParallelMergeLevelMinus2; } + Void setLog2ParallelMergeLevelMinus2 (UInt mrgLevel) { m_log2ParallelMergeLevelMinus2 = mrgLevel; } + Int getNumExtraSliceHeaderBits() { return m_numExtraSliceHeaderBits; } + Void setNumExtraSliceHeaderBits(Int i) { m_numExtraSliceHeaderBits = i; } + Void setLoopFilterAcrossSlicesEnabledFlag ( Bool bValue ) { m_loopFilterAcrossSlicesEnabledFlag = bValue; } + Bool getLoopFilterAcrossSlicesEnabledFlag () { return m_loopFilterAcrossSlicesEnabledFlag; } + Bool getSliceHeaderExtensionPresentFlag () { return m_sliceHeaderExtensionPresentFlag; } + Void setSliceHeaderExtensionPresentFlag (Bool val) { m_sliceHeaderExtensionPresentFlag = val; } +}; + +struct WPScalingParam +{ + // Explicit weighted prediction parameters parsed in slice header, + // or Implicit weighted prediction parameters (8 bits depth values). + Bool bPresentFlag; + UInt uiLog2WeightDenom; + Int iWeight; + Int iOffset; + + // Weighted prediction scaling values built from above parameters (bitdepth scaled): + Int w; + Int o; + Int offset; + Int shift; + Int round; +}; + +struct WPACDCParam +{ + Int64 iAC; + Int64 iDC; +}; + +/// slice header class +class TComSlice +{ + +private: + // Bitstream writing + Bool m_saoEnabledFlag[MAX_NUM_CHANNEL_TYPE]; + Int m_iPPSId; ///< picture parameter set ID + Bool m_PicOutputFlag; ///< pic_output_flag + Int m_iPOC; + Int m_iLastIDR; + Int m_iAssociatedIRAP; + NalUnitType m_iAssociatedIRAPType; + static Int m_prevTid0POC; + TComReferencePictureSet *m_pcRPS; + TComReferencePictureSet m_LocalRPS; + Int m_iBDidx; + TComRefPicListModification m_RefPicListModification; + NalUnitType m_eNalUnitType; ///< Nal unit type for the slice + SliceType m_eSliceType; + Int m_iSliceQp; + Bool m_dependentSliceSegmentFlag; +#if ADAPTIVE_QP_SELECTION + Int m_iSliceQpBase; +#endif + Bool m_ChromaQpAdjEnabled; + Bool m_deblockingFilterDisable; + Bool m_deblockingFilterOverrideFlag; //< offsets for deblocking filter inherit from PPS + Int m_deblockingFilterBetaOffsetDiv2; //< beta offset for deblocking filter + Int m_deblockingFilterTcOffsetDiv2; //< tc offset for deblocking filter + Int m_list1IdxToList0Idx[MAX_NUM_REF]; + Int m_aiNumRefIdx [NUM_REF_PIC_LIST_01]; // for multiple reference of current slice + + Bool m_bCheckLDC; + + // Data + Int m_iSliceQpDelta; + Int m_iSliceChromaQpDelta[MAX_NUM_COMPONENT]; + TComPic* m_apcRefPicList [NUM_REF_PIC_LIST_01][MAX_NUM_REF+1]; + Int m_aiRefPOCList [NUM_REF_PIC_LIST_01][MAX_NUM_REF+1]; + Bool m_bIsUsedAsLongTerm[NUM_REF_PIC_LIST_01][MAX_NUM_REF+1]; + Int m_iDepth; + + // referenced slice? + Bool m_bRefenced; + + // access channel + TComVPS* m_pcVPS; + TComSPS* m_pcSPS; + TComPPS* m_pcPPS; + TComPic* m_pcPic; +#if ADAPTIVE_QP_SELECTION + TComTrQuant* m_pcTrQuant; +#endif + UInt m_colFromL0Flag; // collocated picture from List0 flag + + Bool m_noOutputPriorPicsFlag; + Bool m_noRaslOutputFlag; + Bool m_handleCraAsBlaFlag; + + UInt m_colRefIdx; + UInt m_maxNumMergeCand; + + Double m_lambdas[MAX_NUM_COMPONENT]; + + Bool m_abEqualRef [NUM_REF_PIC_LIST_01][MAX_NUM_REF][MAX_NUM_REF]; + UInt m_uiTLayer; + Bool m_bTLayerSwitchingFlag; + + SliceConstraint m_sliceMode; + UInt m_sliceArgument; + UInt m_sliceCurStartCtuTsAddr; + UInt m_sliceCurEndCtuTsAddr; + UInt m_sliceIdx; + SliceConstraint m_sliceSegmentMode; + UInt m_sliceSegmentArgument; + UInt m_sliceSegmentCurStartCtuTsAddr; + UInt m_sliceSegmentCurEndCtuTsAddr; + Bool m_nextSlice; + Bool m_nextSliceSegment; + UInt m_sliceBits; + UInt m_sliceSegmentBits; + Bool m_bFinalized; + + WPScalingParam m_weightPredTable[NUM_REF_PIC_LIST_01][MAX_NUM_REF][MAX_NUM_COMPONENT]; // [REF_PIC_LIST_0 or REF_PIC_LIST_1][refIdx][0:Y, 1:U, 2:V] + WPACDCParam m_weightACDCParam[MAX_NUM_COMPONENT]; + + std::vector m_substreamSizes; + + TComScalingList* m_scalingList; //!< pointer of quantization matrix + Bool m_cabacInitFlag; + + Bool m_bLMvdL1Zero; + Bool m_temporalLayerNonReferenceFlag; + Bool m_LFCrossSliceBoundaryFlag; + + Bool m_enableTMVPFlag; +public: + TComSlice(); + virtual ~TComSlice(); + Void initSlice (); + Void initTiles(); + + Void setVPS ( TComVPS* pcVPS ) { m_pcVPS = pcVPS; } + TComVPS* getVPS () { return m_pcVPS; } + Void setSPS ( TComSPS* pcSPS ) { m_pcSPS = pcSPS; } + TComSPS* getSPS () { return m_pcSPS; } + const TComSPS* getSPS() const { return m_pcSPS; } + + Void setPPS ( TComPPS* pcPPS ) { assert(pcPPS!=NULL); m_pcPPS = pcPPS; m_iPPSId = pcPPS->getPPSId(); } + TComPPS* getPPS () { return m_pcPPS; } + const TComPPS* getPPS() const { return m_pcPPS; } + +#if ADAPTIVE_QP_SELECTION + Void setTrQuant ( TComTrQuant* pcTrQuant ) { m_pcTrQuant = pcTrQuant; } + TComTrQuant* getTrQuant () { return m_pcTrQuant; } +#endif + + Void setPPSId ( Int PPSId ) { m_iPPSId = PPSId; } + Int getPPSId () { return m_iPPSId; } + Void setPicOutputFlag( Bool b ) { m_PicOutputFlag = b; } + Bool getPicOutputFlag() { return m_PicOutputFlag; } + Void setSaoEnabledFlag(ChannelType chType, Bool s) {m_saoEnabledFlag[chType] =s; } + Bool getSaoEnabledFlag(ChannelType chType) { return m_saoEnabledFlag[chType]; } + Void setRPS ( TComReferencePictureSet *pcRPS ) { m_pcRPS = pcRPS; } + TComReferencePictureSet* getRPS () { return m_pcRPS; } + TComReferencePictureSet* getLocalRPS () { return &m_LocalRPS; } + + Void setRPSidx ( Int iBDidx ) { m_iBDidx = iBDidx; } + Int getRPSidx () { return m_iBDidx; } + Int getPrevTid0POC () { return m_prevTid0POC; } + TComRefPicListModification* getRefPicListModification() { return &m_RefPicListModification; } + Void setLastIDR(Int iIDRPOC) { m_iLastIDR = iIDRPOC; } + Int getLastIDR() { return m_iLastIDR; } + Void setAssociatedIRAPPOC(Int iAssociatedIRAPPOC) { m_iAssociatedIRAP = iAssociatedIRAPPOC; } + Int getAssociatedIRAPPOC() { return m_iAssociatedIRAP; } + Void setAssociatedIRAPType(NalUnitType associatedIRAPType) { m_iAssociatedIRAPType = associatedIRAPType; } + NalUnitType getAssociatedIRAPType() { return m_iAssociatedIRAPType; } + SliceType getSliceType () { return m_eSliceType; } + Int getPOC () { return m_iPOC; } + Int getSliceQp () { return m_iSliceQp; } + Bool getDependentSliceSegmentFlag() const { return m_dependentSliceSegmentFlag; } + Void setDependentSliceSegmentFlag(Bool val) { m_dependentSliceSegmentFlag = val; } +#if ADAPTIVE_QP_SELECTION + Int getSliceQpBase () const { return m_iSliceQpBase; } +#endif + Int getSliceQpDelta () const { return m_iSliceQpDelta; } + Int getSliceChromaQpDelta (ComponentID compID) const { return isLuma(compID) ? 0 : m_iSliceChromaQpDelta[compID]; } + Bool getUseChromaQpAdj() const { return m_ChromaQpAdjEnabled; } + Bool getDeblockingFilterDisable() const { return m_deblockingFilterDisable; } + Bool getDeblockingFilterOverrideFlag() const { return m_deblockingFilterOverrideFlag; } + Int getDeblockingFilterBetaOffsetDiv2() const { return m_deblockingFilterBetaOffsetDiv2; } + Int getDeblockingFilterTcOffsetDiv2() const { return m_deblockingFilterTcOffsetDiv2; } + + Int getNumRefIdx ( RefPicList e ) const { return m_aiNumRefIdx[e]; } + TComPic* getPic () { return m_pcPic; } + TComPic* getRefPic ( RefPicList e, Int iRefIdx) { return m_apcRefPicList[e][iRefIdx]; } + Int getRefPOC ( RefPicList e, Int iRefIdx) { return m_aiRefPOCList[e][iRefIdx]; } + Int getDepth () { return m_iDepth; } + UInt getColFromL0Flag () { return m_colFromL0Flag; } + UInt getColRefIdx () { return m_colRefIdx; } + Void checkColRefIdx (UInt curSliceIdx, TComPic* pic); + Bool getIsUsedAsLongTerm (Int i, Int j) { return m_bIsUsedAsLongTerm[i][j]; } + Void setIsUsedAsLongTerm (Int i, Int j, Bool value) { m_bIsUsedAsLongTerm[i][j] = value; } + Bool getCheckLDC () { return m_bCheckLDC; } + Bool getMvdL1ZeroFlag () { return m_bLMvdL1Zero; } + Int getNumRpsCurrTempList(); + Int getList1IdxToList0Idx ( Int list1Idx ) { return m_list1IdxToList0Idx[list1Idx]; } + Void setReferenced(Bool b) { m_bRefenced = b; } + Bool isReferenced() { return m_bRefenced; } + Bool isReferenceNalu() { return ((getNalUnitType() <= NAL_UNIT_RESERVED_VCL_R15) && (getNalUnitType()%2 != 0)) || ((getNalUnitType() >= NAL_UNIT_CODED_SLICE_BLA_W_LP) && (getNalUnitType() <= NAL_UNIT_RESERVED_IRAP_VCL23) ); } + Void setPOC ( Int i ) { m_iPOC = i; if ((getTLayer()==0) && (isReferenceNalu() && (getNalUnitType()!=NAL_UNIT_CODED_SLICE_RASL_R)&& (getNalUnitType()!=NAL_UNIT_CODED_SLICE_RADL_R))) {m_prevTid0POC=i;} } + Void setNalUnitType ( NalUnitType e ) { m_eNalUnitType = e; } + NalUnitType getNalUnitType () const { return m_eNalUnitType; } + Bool getRapPicFlag (); + Bool getIdrPicFlag () { return getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP; } + Bool isIRAP () const { return (getNalUnitType() >= 16) && (getNalUnitType() <= 23); } + Void checkCRA(TComReferencePictureSet *pReferencePictureSet, Int& pocCRA, NalUnitType& associatedIRAPType, TComList& rcListPic); + Void decodingRefreshMarking(Int& pocCRA, Bool& bRefreshPending, TComList& rcListPic); + Void setSliceType ( SliceType e ) { m_eSliceType = e; } + Void setSliceQp ( Int i ) { m_iSliceQp = i; } +#if ADAPTIVE_QP_SELECTION + Void setSliceQpBase ( Int i ) { m_iSliceQpBase = i; } +#endif + Void setSliceQpDelta ( Int i ) { m_iSliceQpDelta = i; } + Void setSliceChromaQpDelta( ComponentID compID, Int i ) { m_iSliceChromaQpDelta[compID] = isLuma(compID) ? 0 : i; } + Void setUseChromaQpAdj ( Bool b ) { m_ChromaQpAdjEnabled = b; } + Void setDeblockingFilterDisable( Bool b ) { m_deblockingFilterDisable= b; } + Void setDeblockingFilterOverrideFlag( Bool b ) { m_deblockingFilterOverrideFlag = b; } + Void setDeblockingFilterBetaOffsetDiv2( Int i ) { m_deblockingFilterBetaOffsetDiv2 = i; } + Void setDeblockingFilterTcOffsetDiv2( Int i ) { m_deblockingFilterTcOffsetDiv2 = i; } + + Void setRefPic ( TComPic* p, RefPicList e, Int iRefIdx ) { m_apcRefPicList[e][iRefIdx] = p; } + Void setRefPOC ( Int i, RefPicList e, Int iRefIdx ) { m_aiRefPOCList[e][iRefIdx] = i; } + Void setNumRefIdx ( RefPicList e, Int i ) { m_aiNumRefIdx[e] = i; } + Void setPic ( TComPic* p ) { m_pcPic = p; } + Void setDepth ( Int iDepth ) { m_iDepth = iDepth; } + + Void setRefPicList ( TComList& rcListPic, Bool checkNumPocTotalCurr = false ); + Void setRefPOCList (); + Void setColFromL0Flag ( UInt colFromL0 ) { m_colFromL0Flag = colFromL0; } + Void setColRefIdx ( UInt refIdx) { m_colRefIdx = refIdx; } + Void setCheckLDC ( Bool b ) { m_bCheckLDC = b; } + Void setMvdL1ZeroFlag ( Bool b) { m_bLMvdL1Zero = b; } + + Bool isIntra () { return m_eSliceType == I_SLICE; } + Bool isInterB () { return m_eSliceType == B_SLICE; } + Bool isInterP () { return m_eSliceType == P_SLICE; } + + Void setLambdas ( const Double lambdas[MAX_NUM_COMPONENT] ) { for (Int component = 0; component < MAX_NUM_COMPONENT; component++) m_lambdas[component] = lambdas[component]; } + const Double* getLambdas() const { return m_lambdas; } + + Void initEqualRef(); + Bool isEqualRef ( RefPicList e, Int iRefIdx1, Int iRefIdx2 ) + { + assert(e& rcListPic ); + Void setList1IdxToList0Idx(); + + UInt getTLayer () { return m_uiTLayer; } + Void setTLayer ( UInt uiTLayer ) { m_uiTLayer = uiTLayer; } + + Void setTLayerInfo( UInt uiTLayer ); + Void decodingMarking( TComList& rcListPic, Int iGOPSIze, Int& iMaxRefPicNum ); + Void checkLeadingPictureRestrictions( TComList& rcListPic ); + Void applyReferencePictureSet( TComList& rcListPic, TComReferencePictureSet *RPSList); + Bool isTemporalLayerSwitchingPoint( TComList& rcListPic ); + Bool isStepwiseTemporalLayerSwitchingPointCandidate( TComList& rcListPic ); +#if ALLOW_RECOVERY_POINT_AS_RAP + Int checkThatAllRefPicsAreAvailable( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool printErrors, Int pocRandomAccess = 0, Bool bUseRecoveryPoint = false); + Void createExplicitReferencePictureSetFromReference( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP, Int pocRandomAccess = 0, Bool bUseRecoveryPoint = false); +#else + Int checkThatAllRefPicsAreAvailable( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool printErrors, Int pocRandomAccess = 0); + Void createExplicitReferencePictureSetFromReference( TComList& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP); +#endif + Void setMaxNumMergeCand (UInt val ) { m_maxNumMergeCand = val; } + UInt getMaxNumMergeCand () { return m_maxNumMergeCand; } + + Void setNoOutputPriorPicsFlag ( Bool val ) { m_noOutputPriorPicsFlag = val; } + Bool getNoOutputPriorPicsFlag () { return m_noOutputPriorPicsFlag; } + + Void setNoRaslOutputFlag ( Bool val ) { m_noRaslOutputFlag = val; } + Bool getNoRaslOutputFlag () { return m_noRaslOutputFlag; } + + Void setHandleCraAsBlaFlag ( Bool val ) { m_handleCraAsBlaFlag = val; } + Bool getHandleCraAsBlaFlag () { return m_handleCraAsBlaFlag; } + + Void setSliceMode ( SliceConstraint mode ) { m_sliceMode = mode; } + SliceConstraint getSliceMode () const { return m_sliceMode; } + Void setSliceArgument ( UInt uiArgument ) { m_sliceArgument = uiArgument; } + UInt getSliceArgument () { return m_sliceArgument; } + Void setSliceCurStartCtuTsAddr ( UInt ctuTsAddr ) { m_sliceCurStartCtuTsAddr = ctuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + UInt getSliceCurStartCtuTsAddr () const { return m_sliceCurStartCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + Void setSliceCurEndCtuTsAddr ( UInt ctuTsAddr ) { m_sliceCurEndCtuTsAddr = ctuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + UInt getSliceCurEndCtuTsAddr () const { return m_sliceCurEndCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + Void setSliceIdx ( UInt i) { m_sliceIdx = i; } + UInt getSliceIdx () { return m_sliceIdx; } + Void copySliceInfo (TComSlice *pcSliceSrc); + Void setSliceSegmentMode ( SliceConstraint mode ) { m_sliceSegmentMode = mode; } + SliceConstraint getSliceSegmentMode () const { return m_sliceSegmentMode; } + Void setSliceSegmentArgument ( UInt uiArgument ) { m_sliceSegmentArgument = uiArgument; } + UInt getSliceSegmentArgument () { return m_sliceSegmentArgument; } + Void setSliceSegmentCurStartCtuTsAddr ( UInt ctuTsAddr ) { m_sliceSegmentCurStartCtuTsAddr = ctuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + UInt getSliceSegmentCurStartCtuTsAddr () const { return m_sliceSegmentCurStartCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + Void setSliceSegmentCurEndCtuTsAddr ( UInt ctuTsAddr ) { m_sliceSegmentCurEndCtuTsAddr = ctuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + UInt getSliceSegmentCurEndCtuTsAddr () const { return m_sliceSegmentCurEndCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) + Void setSliceBits ( UInt uiVal ) { m_sliceBits = uiVal; } + UInt getSliceBits () { return m_sliceBits; } + Void setSliceSegmentBits ( UInt uiVal ) { m_sliceSegmentBits = uiVal; } + UInt getSliceSegmentBits () { return m_sliceSegmentBits; } + Void setFinalized ( Bool uiVal ) { m_bFinalized = uiVal; } + Bool getFinalized () { return m_bFinalized; } + Void setWpScaling ( WPScalingParam wp[NUM_REF_PIC_LIST_01][MAX_NUM_REF][MAX_NUM_COMPONENT] ) { memcpy(m_weightPredTable, wp, sizeof(WPScalingParam)*NUM_REF_PIC_LIST_01*MAX_NUM_REF*MAX_NUM_COMPONENT); } + Void getWpScaling ( RefPicList e, Int iRefIdx, WPScalingParam *&wp); + + Void resetWpScaling (); + Void initWpScaling (); + inline Bool applyWP () { return( (m_eSliceType==P_SLICE && m_pcPPS->getUseWP()) || (m_eSliceType==B_SLICE && m_pcPPS->getWPBiPred()) ); } + + Void setWpAcDcParam ( WPACDCParam wp[MAX_NUM_COMPONENT] ) { memcpy(m_weightACDCParam, wp, sizeof(WPACDCParam)*MAX_NUM_COMPONENT); } + Void getWpAcDcParam ( WPACDCParam *&wp ); + Void initWpAcDcParam (); + + Void clearSubstreamSizes ( ) { return m_substreamSizes.clear(); } + UInt getNumberOfSubstreamSizes ( ) { return (UInt) m_substreamSizes.size(); } + Void addSubstreamSize ( UInt size ) { m_substreamSizes.push_back(size); } + UInt getSubstreamSize ( Int idx ) { assert(idx& rcListPic, Int poc); + TComPic* xGetLongTermRefPic(TComList& rcListPic, Int poc, Bool pocHasMsb); +};// END CLASS DEFINITION TComSlice + + +template class ParameterSetMap +{ +public: + ParameterSetMap(Int maxId) + :m_maxId (maxId) + {} + + ~ParameterSetMap() + { + for (typename std::map::iterator i = m_paramsetMap.begin(); i!= m_paramsetMap.end(); i++) + { + delete (*i).second; + } + } + + Void storePS(Int psId, T *ps) + { + assert ( psId < m_maxId ); + if ( m_paramsetMap.find(psId) != m_paramsetMap.end() ) + { + delete m_paramsetMap[psId]; + } + m_paramsetMap[psId] = ps; + } + + Void mergePSList(ParameterSetMap &rPsList) + { + for (typename std::map::iterator i = rPsList.m_paramsetMap.begin(); i!= rPsList.m_paramsetMap.end(); i++) + { + storePS(i->first, i->second); + } + rPsList.m_paramsetMap.clear(); + } + + + T* getPS(Int psId) + { + return ( m_paramsetMap.find(psId) == m_paramsetMap.end() ) ? NULL : m_paramsetMap[psId]; + } + + T* getFirstPS() + { + return (m_paramsetMap.begin() == m_paramsetMap.end() ) ? NULL : m_paramsetMap.begin()->second; + } + +private: + std::map m_paramsetMap; + Int m_maxId; +}; + +class ParameterSetManager +{ +public: + ParameterSetManager(); + virtual ~ParameterSetManager(); + + //! store sequence parameter set and take ownership of it + Void storeVPS(TComVPS *vps) { m_vpsMap.storePS( vps->getVPSId(), vps); }; + //! get pointer to existing video parameter set + TComVPS* getVPS(Int vpsId) { return m_vpsMap.getPS(vpsId); }; + TComVPS* getFirstVPS() { return m_vpsMap.getFirstPS(); }; + + //! store sequence parameter set and take ownership of it + Void storeSPS(TComSPS *sps) { m_spsMap.storePS( sps->getSPSId(), sps); }; + //! get pointer to existing sequence parameter set + TComSPS* getSPS(Int spsId) { return m_spsMap.getPS(spsId); }; + TComSPS* getFirstSPS() { return m_spsMap.getFirstPS(); }; + + //! store picture parameter set and take ownership of it + Void storePPS(TComPPS *pps) { m_ppsMap.storePS( pps->getPPSId(), pps); }; + //! get pointer to existing picture parameter set + TComPPS* getPPS(Int ppsId) { return m_ppsMap.getPS(ppsId); }; + TComPPS* getFirstPPS() { return m_ppsMap.getFirstPS(); }; + + //! activate a SPS from a active parameter sets SEI message + //! \returns true, if activation is successful + Bool activateSPSWithSEI(Int SPSId); + + //! activate a PPS and depending on isIDR parameter also SPS and VPS + //! \returns true, if activation is successful + Bool activatePPS(Int ppsId, Bool isIRAP); + + TComVPS* getActiveVPS(){ return m_vpsMap.getPS(m_activeVPSId); }; + TComSPS* getActiveSPS(){ return m_spsMap.getPS(m_activeSPSId); }; + TComPPS* getActivePPS(){ return m_ppsMap.getPS(m_activePPSId); }; + +protected: + + ParameterSetMap m_vpsMap; + ParameterSetMap m_spsMap; + ParameterSetMap m_ppsMap; + + Int m_activeVPSId; + Int m_activeSPSId; + Int m_activePPSId; +}; + +//! \} + +#endif // __TCOMSLICE__ diff --git a/jctvc/TLibCommon/TComTU.cpp b/jctvc/TLibCommon/TComTU.cpp new file mode 100644 index 0000000..a9a5db5 --- /dev/null +++ b/jctvc/TLibCommon/TComTU.cpp @@ -0,0 +1,254 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "TComTU.h" +#include "TComRom.h" +#include "TComDataCU.h" +#include "TComPic.h" + +//---------------------------------------------------------------------------------------------------------------------- + +/*static*/ const UInt TComTU::NUMBER_OF_SECTIONS[TComTU::NUMBER_OF_SPLIT_MODES] = { 1, 2, 4 }; + +static const UInt partIdxStepShift [TComTU::NUMBER_OF_SPLIT_MODES] = { 0, 1, 2 }; + +//---------------------------------------------------------------------------------------------------------------------- + +TComTU::TComTU(TComDataCU *pcCU, const UInt absPartIdxCU, const UInt cuDepth, const UInt initTrDepthRelCU) + : mChromaFormat(pcCU->getSlice()->getSPS()->getChromaFormatIdc()), + mbProcessLastOfLevel(true), // does not matter. the top level is not 4 quadrants. + mCuDepth(cuDepth), + mSection(0), + mSplitMode(DONT_SPLIT), + mAbsPartIdxCU(absPartIdxCU), + mAbsPartIdxTURelCU(0), + mAbsPartIdxStep(pcCU->getPic()->getNumPartitionsInCtu() >> (pcCU->getDepth(absPartIdxCU)<<1)), + mpcCU(pcCU), + mLog2TrLumaSize(0), + mpParent(NULL) +{ + TComSPS *pSPS=pcCU->getSlice()->getSPS(); + mLog2TrLumaSize = g_aucConvertToBit[pSPS->getMaxCUWidth() >> (mCuDepth+initTrDepthRelCU)]+2; + + const UInt baseOffset444=pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight()*absPartIdxCU; + + for(UInt i=0; igetWidth( absPartIdxCU) >> csx) : 0; + mRect[i].height = (i < getNumberValidComponents(mChromaFormat)) ? (pcCU->getHeight(absPartIdxCU) >> csy) : 0; + mRect[i].x0=0; + mRect[i].y0=0; + mCodeAll[i]=true; + mOffsets[i]=baseOffset444>>(csx+csy); + } +} + + + +TComTURecurse::TComTURecurse( TComDataCU *pcCU, + const UInt absPartIdxCU) + : TComTU(pcCU, absPartIdxCU, pcCU->getDepth(absPartIdxCU), 0) +{ } + + + +TComTU::TComTU(TComTU &parent, const Bool bProcessLastOfLevel, const TU_SPLIT_MODE splitMode, const Bool splitAtCurrentDepth, const ComponentID absPartIdxSourceComponent) + : mChromaFormat(parent.mChromaFormat), + mbProcessLastOfLevel(bProcessLastOfLevel), + mCuDepth(parent.mCuDepth), + mSection(0), + mSplitMode(splitMode), + mAbsPartIdxCU(parent.mAbsPartIdxCU), + mAbsPartIdxTURelCU(parent.GetRelPartIdxTU(absPartIdxSourceComponent)), + mAbsPartIdxStep(std::max(1, (parent.GetAbsPartIdxNumParts(absPartIdxSourceComponent) >> partIdxStepShift[splitMode]))), + mpcCU(parent.mpcCU), + mLog2TrLumaSize(parent.mLog2TrLumaSize - ((splitMode != QUAD_SPLIT) ? 0 : 1)), //no change in width for vertical split + mpParent(&parent) +{ + for(UInt i=0; i>1; + mOffsets[i]=parent.mOffsets[i]; + mCodeAll[i]=true; // The 2 TUs at this level is coded. + mOrigWidth[i]=mRect[i].width; + } + return; + } + + for(UInt i=0; i> 1); + mRect[i].height= (parent.mRect[i].height>> 1); + mRect[i].x0=parent.mRect[i].x0; + mRect[i].y0=parent.mRect[i].y0; + mOffsets[i]=parent.mOffsets[i]; + + if ((mRect[i].width < MIN_TU_SIZE || mRect[i].height < MIN_TU_SIZE) && mRect[i].width!=0) + { + const UInt numPels=mRect[i].width * mRect[i].height; + if (numPels < (MIN_TU_SIZE*MIN_TU_SIZE)) + { + // this level doesn't have enough pixels to have 4 blocks of any relative dimension + mRect[i].width = parent.mRect[i].width; + mRect[i].height= parent.mRect[i].height; + mCodeAll[i]=false; // go up a level, so only process one entry of a quadrant + mTrDepthRelCU[i]--; + } + else if (mRect[i].width < mRect[i].height) + { + mRect[i].width=MIN_TU_SIZE; + mRect[i].height=numPels/MIN_TU_SIZE; + mCodeAll[i]=true; + } + else + { + mRect[i].height=MIN_TU_SIZE; + mRect[i].width=numPels/MIN_TU_SIZE; + mCodeAll[i]=true; + } + } + else + { + mCodeAll[i]=true; + } + + mOrigWidth[i]=mRect[i].width; + if (!mCodeAll[i] && mbProcessLastOfLevel) mRect[i].width=0; + } +} + +Bool TComTURecurse::nextSection(const TComTU &parent) +{ + if (mSplitMode==DONT_SPLIT) + { + mSection++; + return false; + } + else + { + for(UInt i=0; i= parentRect.x0+parentRect.width) + { + mRect[i].x0=parentRect.x0; + mRect[i].y0+=mRect[i].height; + } + if (!mCodeAll[i]) + { + if (!mbProcessLastOfLevel || mSection!=2) mRect[i].width=0; + } + } + assert(mRect[COMPONENT_Cb].x0==mRect[COMPONENT_Cr].x0); + assert(mRect[COMPONENT_Cb].y0==mRect[COMPONENT_Cr].y0); + assert(mRect[COMPONENT_Cb].width==mRect[COMPONENT_Cr].width); + assert(mRect[COMPONENT_Cb].height==mRect[COMPONENT_Cr].height); + + mAbsPartIdxTURelCU+=mAbsPartIdxStep; + mSection++; + return mSection< (1<isIntra(absPartIdx); +} + + +Bool TComTU::isNonTransformedResidualRotated(const ComponentID compID) +{ + // rotation only for 4x4 intra, and is only used for non-transformed blocks (the latter is not checked here) + return getCU()->getSlice()->getSPS()->getUseResidualRotation() + && mRect[compID].width == 4 + && getCU()->isIntra(GetAbsPartIdxTU()); +} + + +UInt TComTU::getGolombRiceStatisticsIndex(const ComponentID compID) +{ + TComDataCU *const pcCU = getCU(); + const UInt absPartIdx = GetAbsPartIdxTU(compID); + const Bool transformSkip = pcCU->getTransformSkip(absPartIdx, compID); + const Bool transquantBypass = pcCU->getCUTransquantBypass(absPartIdx); + + //-------- + + const UInt channelTypeOffset = isChroma(compID) ? 2 : 0; + const UInt nonTransformedOffset = (transformSkip || transquantBypass) ? 1 : 0; + + //-------- + + const UInt selectedIndex = channelTypeOffset + nonTransformedOffset; + assert(selectedIndex < RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS); + + return selectedIndex; +} diff --git a/jctvc/TLibCommon/TComTU.h b/jctvc/TLibCommon/TComTU.h new file mode 100644 index 0000000..0f15aa6 --- /dev/null +++ b/jctvc/TLibCommon/TComTU.h @@ -0,0 +1,167 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TCOMTU__ +#define __TCOMTU__ + +class TComTU; // forward declaration + +#include "CommonDef.h" +#include "TComRectangle.h" +#include "TComChromaFormat.h" + +class TComDataCU; // forward declaration + +//---------------------------------------------------------------------------------------------------------------------- + + +class TComTU +{ + public: + typedef enum TU_SPLIT_MODE { DONT_SPLIT=0, VERTICAL_SPLIT=1, QUAD_SPLIT=2, NUMBER_OF_SPLIT_MODES=3 } SPLIT_MODE; + + static const UInt NUMBER_OF_SECTIONS[NUMBER_OF_SPLIT_MODES]; + + protected: + ChromaFormat mChromaFormat; + Bool mbProcessLastOfLevel; // if true, then if size n/2 x n/2 is invalid, the nxn block for a channel is processed only for the last block, not the first. + UInt mCuDepth; + UInt mTrDepthRelCU[MAX_NUM_COMPONENT]; + UInt mSection; + TU_SPLIT_MODE mSplitMode; + TComRectangle mRect[MAX_NUM_COMPONENT]; + Bool mCodeAll[MAX_NUM_COMPONENT]; + UInt mOrigWidth[MAX_NUM_COMPONENT]; + UInt mOffsets[MAX_NUM_COMPONENT]; + UInt mAbsPartIdxCU; + UInt mAbsPartIdxTURelCU; + UInt mAbsPartIdxStep; + TComDataCU *mpcCU; + UInt mLog2TrLumaSize; + TComTU *mpParent; + + TComTU(const TComTU &); // not defined - do not use + TComTU&operator=(const TComTU &); // not defined - do not use + + public: + TComTU( TComDataCU *pcCU, + const UInt absPartIdxCU, + const UInt cuDepth, + const UInt initTrDepthRelCU); + + protected: + TComTU( TComTU &parentLevel, + const Bool bProcessLastOfLevel, + const TU_SPLIT_MODE splitMode = QUAD_SPLIT, + const Bool splitAtCurrentDepth = false, + const ComponentID absPartIdxSourceComponent = COMPONENT_Y + ); + + public: + TComTU *Parent() { return mpParent; } + const TComTU *Parent() const { return mpParent; } + + UInt getCoefficientOffset(const ComponentID compID) const { return mOffsets[compID]; } + + const TComRectangle &getRect(const ComponentID compID) const { return mRect[compID]; } + + Bool ProcessingAllQuadrants(const ComponentID compID) const { return mCodeAll[compID]; } + Bool ProcessComponentSection(const ComponentID compID) const { return mRect[compID].width != 0; } + Bool ProcessChannelSection(const ChannelType chType) const { return mRect[chType].width != 0; } + UInt GetSectionNumber() const { return mSection; } + + UInt getCUDepth() const { return mCuDepth; } + + UInt GetTransformDepthTotal() const { return mCuDepth+GetTransformDepthRel(); } + UInt GetTransformDepthTotalAdj(const ComponentID compID) const { return mCuDepth+GetTransformDepthRelAdj(compID); } + + UInt GetTransformDepthRel() const { return mTrDepthRelCU[COMPONENT_Y]; } + UInt GetTransformDepthRelAdj(const ComponentID compID) const { return mTrDepthRelCU[compID]; } + UInt GetTransformDepthRelAdj(const ChannelType chType) const + { + assert(isLuma(chType) || (mTrDepthRelCU[COMPONENT_Cb] == mTrDepthRelCU[COMPONENT_Cr])); + return mTrDepthRelCU[isLuma(chType) ? COMPONENT_Y : COMPONENT_Cb]; + } + + UInt GetAbsPartIdxCU() const { return mAbsPartIdxCU; } + UInt GetRelPartIdxTU() const { return mAbsPartIdxTURelCU; } + UInt GetRelPartIdxTU(const ComponentID compID) const { return ProcessingAllQuadrants(compID) ? mAbsPartIdxTURelCU : (mAbsPartIdxTURelCU & (~0x3)); } + UInt GetAbsPartIdxTU() const { return GetAbsPartIdxCU() + GetRelPartIdxTU(); } + UInt GetAbsPartIdxTU(const ComponentID compID) const { return GetAbsPartIdxCU() + GetRelPartIdxTU(compID); } + UInt GetAbsPartIdxNumParts() const { return mAbsPartIdxStep; } + UInt GetAbsPartIdxNumParts(const ComponentID compID) const { return ProcessingAllQuadrants(compID) ? mAbsPartIdxStep : (mAbsPartIdxStep * NUMBER_OF_SECTIONS[mSplitMode]); } + + ChromaFormat GetChromaFormat() const { return mChromaFormat; } + + TComDataCU *getCU() { return mpcCU; } + const TComDataCU *getCU() const { return mpcCU; } + Bool IsLastSection() const { return mSection+1>=((1<getDepth(idx) + + TComTURecurse( TComTU &parentLevel, //Parent TU from which recursion children are derived + const Bool bProcessLastOfLevel, //If true (and the split results in a "step-up" for chroma), the chroma TU is colocated with the last luma TU instead of the first + const TU_SPLIT_MODE splitMode = QUAD_SPLIT, //DONT_SPLIT = create one new TU as a copy of its parent, VERTICAL_SPLIT = split the TU into top and bottom halves, QUAD_SPLIT = split the TU into four equal quadrants + const Bool splitAtCurrentDepth = false, //Set true to keep the current depth when applying a vertical or quad split + const ComponentID absPartIdxSourceComponent = COMPONENT_Y //Specifies which component of the parent TU should be used to initialise the absPartIdx of the first child and the absPartIdx step (this is needed when splitting a "stepped-up" chroma TU) + ) + : TComTU(parentLevel, bProcessLastOfLevel, splitMode, splitAtCurrentDepth, absPartIdxSourceComponent) { } + + Bool nextSection(const TComTU &parent); // returns true if there is another section to process, and prepares internal structures, else returns false +}; + +//---------------------------------------------------------------------------------------------------------------------- + +#endif diff --git a/jctvc/TLibCommon/TComTrQuant.cpp b/jctvc/TLibCommon/TComTrQuant.cpp new file mode 100644 index 0000000..62cc8dc --- /dev/null +++ b/jctvc/TLibCommon/TComTrQuant.cpp @@ -0,0 +1,3333 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComTrQuant.cpp + \brief transform and quantization class +*/ + +#include +#include +#include +#include +#include "TComTrQuant.h" +#include "TComPic.h" +#include "ContextTables.h" +#include "TComTU.h" +#include "Debug.h" + +typedef struct +{ + Int iNNZbeforePos0; + Double d64CodedLevelandDist; // distortion and level cost only + Double d64UncodedDist; // all zero coded block distortion + Double d64SigCost; + Double d64SigCost_0; +} coeffGroupRDStats; + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +#define RDOQ_CHROMA 1 ///< use of RDOQ in chroma + + +// ==================================================================================================================== +// QpParam constructor +// ==================================================================================================================== + +QpParam::QpParam(const Int qpy, + const ChannelType chType, + const Int qpBdOffset, + const Int chromaQPOffset, + const ChromaFormat chFmt ) +{ + Int baseQp; + + if(isLuma(chType)) + { + baseQp = qpy + qpBdOffset; + } + else + { + baseQp = Clip3( -qpBdOffset, (chromaQPMappingTableSize - 1), qpy + chromaQPOffset ); + + if(baseQp < 0) + { + baseQp = baseQp + qpBdOffset; + } + else + { + baseQp = getScaledChromaQP(baseQp, chFmt) + qpBdOffset; + } + } + + Qp =baseQp; + per=baseQp/6; + rem=baseQp%6; +} + +QpParam::QpParam(const TComDataCU &cu, const ComponentID compID) +{ + Int chromaQpOffset = 0; + + if (isChroma(compID)) + { + chromaQpOffset += cu.getSlice()->getPPS()->getQpOffset(compID); + chromaQpOffset += cu.getSlice()->getSliceChromaQpDelta(compID); + + chromaQpOffset += cu.getSlice()->getPPS()->getChromaQpAdjTableAt(cu.getChromaQpAdj(0)).u.offset[Int(compID)-1]; + } + + *this = QpParam(cu.getQP( 0 ), + toChannelType(compID), + cu.getSlice()->getSPS()->getQpBDOffset(toChannelType(compID)), + chromaQpOffset, + cu.getPic()->getChromaFormat()); +} + + +// ==================================================================================================================== +// TComTrQuant class member functions +// ==================================================================================================================== + +TComTrQuant::TComTrQuant() +{ + // allocate temporary buffers + m_plTempCoeff = new TCoeff[ MAX_CU_SIZE*MAX_CU_SIZE ]; + + // allocate bit estimation class (for RDOQ) + m_pcEstBitsSbac = new estBitsSbacStruct; + initScalingList(); +} + +TComTrQuant::~TComTrQuant() +{ + // delete temporary buffers + if ( m_plTempCoeff ) + { + delete [] m_plTempCoeff; + m_plTempCoeff = NULL; + } + + // delete bit estimation class + if ( m_pcEstBitsSbac ) + { + delete m_pcEstBitsSbac; + } + destroyScalingList(); +} + +#if ADAPTIVE_QP_SELECTION +Void TComTrQuant::storeSliceQpNext(TComSlice* pcSlice) +{ + // NOTE: does this work with negative QPs or when some blocks are transquant-bypass enabled? + + Int qpBase = pcSlice->getSliceQpBase(); + Int sliceQpused = pcSlice->getSliceQp(); + Int sliceQpnext; + Double alpha = qpBase < 17 ? 0.5 : 1; + + Int cnt=0; + for(Int u=1; u<=LEVEL_RANGE; u++) + { + cnt += m_sliceNsamples[u] ; + } + + if( !m_useRDOQ ) + { + sliceQpused = qpBase; + alpha = 0.5; + } + + if( cnt > 120 ) + { + Double sum = 0; + Int k = 0; + for(Int u=1; u0) ? (1<<(shift_1st-1)) : 0; + const Int add_2nd = 1<<(shift_2nd-1); + + /* Horizontal transform */ + + for (i=0; i>shift_1st; + } + } + + /* Vertical transform */ + for (i=0; i>shift_2nd; + } + } +} + +/** NxN inverse transform (2D) using brute force matrix multiplication (3 nested loops) + * \param coeff pointer to input data (transform coefficients) + * \param block pointer to output data (residual) + * \param uiStride stride of output data + * \param uiTrSize transform size (uiTrSize x uiTrSize) + * \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only + */ +Void xITr(Int bitDepth, TCoeff *coeff, Pel *block, UInt uiStride, UInt uiTrSize, Bool useDST, const Int maxTrDynamicRange) +{ + UInt i,j,k; + TCoeff iSum; + TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE]; + const TMatrixCoeff *iT; + + if (uiTrSize==4) + { + iT = (useDST ? g_as_DST_MAT_4[TRANSFORM_INVERSE][0] : g_aiT4[TRANSFORM_INVERSE][0]); + } + else if (uiTrSize==8) + { + iT = g_aiT8[TRANSFORM_INVERSE][0]; + } + else if (uiTrSize==16) + { + iT = g_aiT16[TRANSFORM_INVERSE][0]; + } + else if (uiTrSize==32) + { + iT = g_aiT32[TRANSFORM_INVERSE][0]; + } + else + { + assert(0); + } + + static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE]; + + const Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2nd + const Int shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxTrDynamicRange - 1) - bitDepth; + const TCoeff clipMinimum = -(1 << maxTrDynamicRange); + const TCoeff clipMaximum = (1 << maxTrDynamicRange) - 1; + assert(shift_2nd>=0); + const Int add_1st = 1<<(shift_1st-1); + const Int add_2nd = (shift_2nd>0) ? (1<<(shift_2nd-1)) : 0; + + /* Horizontal transform */ + for (i=0; i(clipMinimum, clipMaximum, (iSum + add_1st)>>shift_1st); + } + } + + /* Vertical transform */ + for (i=0; i(std::numeric_limits::min(), std::numeric_limits::max(), (iSum + add_2nd)>>shift_2nd); + } + } +} + +#endif //MATRIX_MULT + + +/** 4x4 forward transform implemented using partial butterfly structure (1D) + * \param src input data (residual) + * \param dst output data (transform coefficients) + * \param shift specifies right shift after 1D transform + */ +Void partialButterfly4(TCoeff *src, TCoeff *dst, Int shift, Int line) +{ + Int j; + TCoeff E[2],O[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift; + dst[2*line] = (g_aiT4[TRANSFORM_FORWARD][2][0]*E[0] + g_aiT4[TRANSFORM_FORWARD][2][1]*E[1] + add)>>shift; + dst[line] = (g_aiT4[TRANSFORM_FORWARD][1][0]*O[0] + g_aiT4[TRANSFORM_FORWARD][1][1]*O[1] + add)>>shift; + dst[3*line] = (g_aiT4[TRANSFORM_FORWARD][3][0]*O[0] + g_aiT4[TRANSFORM_FORWARD][3][1]*O[1] + add)>>shift; + + src += 4; + dst ++; + } +} + +// Fast DST Algorithm. Full matrix multiplication for DST and Fast DST algorithm +// give identical results +Void fastForwardDst(TCoeff *block, TCoeff *coeff, Int shift) // input block, output coeff +{ + Int i; + TCoeff c[4]; + TCoeff rnd_factor = (shift > 0) ? (1<<(shift-1)) : 0; + for (i=0; i<4; i++) + { + // Intermediate Variables + c[0] = block[4*i+0]; + c[1] = block[4*i+1]; + c[2] = block[4*i+2]; + c[3] = block[4*i+3]; + + for (Int row = 0; row < 4; row++) + { + TCoeff result = 0; + for (Int column = 0; column < 4; column++) + result += c[column] * g_as_DST_MAT_4[TRANSFORM_FORWARD][row][column]; // use the defined matrix, rather than hard-wired numbers + + coeff[(row * 4) + i] = rightShift((result + rnd_factor), shift); + } + } +} + +Void fastInverseDst(TCoeff *tmp, TCoeff *block, Int shift, const TCoeff outputMinimum, const TCoeff outputMaximum) // input tmp, output block +{ + Int i; + TCoeff c[4]; + TCoeff rnd_factor = (shift > 0) ? (1<<(shift-1)) : 0; + for (i=0; i<4; i++) + { + // Intermediate Variables + c[0] = tmp[ i]; + c[1] = tmp[4 +i]; + c[2] = tmp[8 +i]; + c[3] = tmp[12+i]; + + for (Int column = 0; column < 4; column++) + { + TCoeff &result = block[(i * 4) + column]; + + result = 0; + for (Int row = 0; row < 4; row++) + result += c[row] * g_as_DST_MAT_4[TRANSFORM_INVERSE][row][column]; // use the defined matrix, rather than hard-wired numbers + + result = Clip3( outputMinimum, outputMaximum, rightShift((result + rnd_factor), shift)); + } + } +} + +/** 4x4 inverse transform implemented using partial butterfly structure (1D) + * \param src input data (transform coefficients) + * \param dst output data (residual) + * \param shift specifies right shift after 1D transform + */ +Void partialButterflyInverse4(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum) +{ + Int j; + TCoeff E[2],O[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift ); + dst[1] = Clip3( outputMinimum, outputMaximum, (E[1] + O[1] + add)>>shift ); + dst[2] = Clip3( outputMinimum, outputMaximum, (E[1] - O[1] + add)>>shift ); + dst[3] = Clip3( outputMinimum, outputMaximum, (E[0] - O[0] + add)>>shift ); + + src ++; + dst += 4; + } +} + +/** 8x8 forward transform implemented using partial butterfly structure (1D) + * \param src input data (residual) + * \param dst output data (transform coefficients) + * \param shift specifies right shift after 1D transform + */ +Void partialButterfly8(TCoeff *src, TCoeff *dst, Int shift, Int line) +{ + Int j,k; + TCoeff E[4],O[4]; + TCoeff EE[2],EO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift; + dst[4*line] = (g_aiT8[TRANSFORM_FORWARD][4][0]*EE[0] + g_aiT8[TRANSFORM_FORWARD][4][1]*EE[1] + add)>>shift; + dst[2*line] = (g_aiT8[TRANSFORM_FORWARD][2][0]*EO[0] + g_aiT8[TRANSFORM_FORWARD][2][1]*EO[1] + add)>>shift; + dst[6*line] = (g_aiT8[TRANSFORM_FORWARD][6][0]*EO[0] + g_aiT8[TRANSFORM_FORWARD][6][1]*EO[1] + add)>>shift; + + dst[line] = (g_aiT8[TRANSFORM_FORWARD][1][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][1][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][1][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][1][3]*O[3] + add)>>shift; + dst[3*line] = (g_aiT8[TRANSFORM_FORWARD][3][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][3][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][3][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][3][3]*O[3] + add)>>shift; + dst[5*line] = (g_aiT8[TRANSFORM_FORWARD][5][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][5][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][5][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][5][3]*O[3] + add)>>shift; + dst[7*line] = (g_aiT8[TRANSFORM_FORWARD][7][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][7][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][7][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][7][3]*O[3] + add)>>shift; + + src += 8; + dst ++; + } +} + +/** 8x8 inverse transform implemented using partial butterfly structure (1D) + * \param src input data (transform coefficients) + * \param dst output data (residual) + * \param shift specifies right shift after 1D transform + */ +Void partialButterflyInverse8(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum) +{ + Int j,k; + TCoeff E[4],O[4]; + TCoeff EE[2],EO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift ); + dst[ k+4 ] = Clip3( outputMinimum, outputMaximum, (E[3-k] - O[3-k] + add)>>shift ); + } + src ++; + dst += 8; + } +} + +/** 16x16 forward transform implemented using partial butterfly structure (1D) + * \param src input data (residual) + * \param dst output data (transform coefficients) + * \param shift specifies right shift after 1D transform + */ +Void partialButterfly16(TCoeff *src, TCoeff *dst, Int shift, Int line) +{ + Int j,k; + TCoeff E[8],O[8]; + TCoeff EE[4],EO[4]; + TCoeff EEE[2],EEO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift; + dst[ 8*line ] = (g_aiT16[TRANSFORM_FORWARD][ 8][0]*EEE[0] + g_aiT16[TRANSFORM_FORWARD][ 8][1]*EEE[1] + add)>>shift; + dst[ 4*line ] = (g_aiT16[TRANSFORM_FORWARD][ 4][0]*EEO[0] + g_aiT16[TRANSFORM_FORWARD][ 4][1]*EEO[1] + add)>>shift; + dst[ 12*line] = (g_aiT16[TRANSFORM_FORWARD][12][0]*EEO[0] + g_aiT16[TRANSFORM_FORWARD][12][1]*EEO[1] + add)>>shift; + + for (k=2;k<16;k+=4) + { + dst[ k*line ] = (g_aiT16[TRANSFORM_FORWARD][k][0]*EO[0] + g_aiT16[TRANSFORM_FORWARD][k][1]*EO[1] + + g_aiT16[TRANSFORM_FORWARD][k][2]*EO[2] + g_aiT16[TRANSFORM_FORWARD][k][3]*EO[3] + add)>>shift; + } + + for (k=1;k<16;k+=2) + { + dst[ k*line ] = (g_aiT16[TRANSFORM_FORWARD][k][0]*O[0] + g_aiT16[TRANSFORM_FORWARD][k][1]*O[1] + + g_aiT16[TRANSFORM_FORWARD][k][2]*O[2] + g_aiT16[TRANSFORM_FORWARD][k][3]*O[3] + + g_aiT16[TRANSFORM_FORWARD][k][4]*O[4] + g_aiT16[TRANSFORM_FORWARD][k][5]*O[5] + + g_aiT16[TRANSFORM_FORWARD][k][6]*O[6] + g_aiT16[TRANSFORM_FORWARD][k][7]*O[7] + add)>>shift; + } + + src += 16; + dst ++; + + } +} + +/** 16x16 inverse transform implemented using partial butterfly structure (1D) + * \param src input data (transform coefficients) + * \param dst output data (residual) + * \param shift specifies right shift after 1D transform + */ +Void partialButterflyInverse16(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum) +{ + Int j,k; + TCoeff E[8],O[8]; + TCoeff EE[4],EO[4]; + TCoeff EEE[2],EEO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift ); + dst[k+8] = Clip3( outputMinimum, outputMaximum, (E[7-k] - O[7-k] + add)>>shift ); + } + src ++; + dst += 16; + } +} + +/** 32x32 forward transform implemented using partial butterfly structure (1D) + * \param src input data (residual) + * \param dst output data (transform coefficients) + * \param shift specifies right shift after 1D transform + */ +Void partialButterfly32(TCoeff *src, TCoeff *dst, Int shift, Int line) +{ + Int j,k; + TCoeff E[16],O[16]; + TCoeff EE[8],EO[8]; + TCoeff EEE[4],EEO[4]; + TCoeff EEEE[2],EEEO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift; + dst[ 16*line ] = (g_aiT32[TRANSFORM_FORWARD][16][0]*EEEE[0] + g_aiT32[TRANSFORM_FORWARD][16][1]*EEEE[1] + add)>>shift; + dst[ 8*line ] = (g_aiT32[TRANSFORM_FORWARD][ 8][0]*EEEO[0] + g_aiT32[TRANSFORM_FORWARD][ 8][1]*EEEO[1] + add)>>shift; + dst[ 24*line ] = (g_aiT32[TRANSFORM_FORWARD][24][0]*EEEO[0] + g_aiT32[TRANSFORM_FORWARD][24][1]*EEEO[1] + add)>>shift; + for (k=4;k<32;k+=8) + { + dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][0]*EEO[0] + g_aiT32[TRANSFORM_FORWARD][k][1]*EEO[1] + + g_aiT32[TRANSFORM_FORWARD][k][2]*EEO[2] + g_aiT32[TRANSFORM_FORWARD][k][3]*EEO[3] + add)>>shift; + } + for (k=2;k<32;k+=4) + { + dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][0]*EO[0] + g_aiT32[TRANSFORM_FORWARD][k][1]*EO[1] + + g_aiT32[TRANSFORM_FORWARD][k][2]*EO[2] + g_aiT32[TRANSFORM_FORWARD][k][3]*EO[3] + + g_aiT32[TRANSFORM_FORWARD][k][4]*EO[4] + g_aiT32[TRANSFORM_FORWARD][k][5]*EO[5] + + g_aiT32[TRANSFORM_FORWARD][k][6]*EO[6] + g_aiT32[TRANSFORM_FORWARD][k][7]*EO[7] + add)>>shift; + } + for (k=1;k<32;k+=2) + { + dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][ 0]*O[ 0] + g_aiT32[TRANSFORM_FORWARD][k][ 1]*O[ 1] + + g_aiT32[TRANSFORM_FORWARD][k][ 2]*O[ 2] + g_aiT32[TRANSFORM_FORWARD][k][ 3]*O[ 3] + + g_aiT32[TRANSFORM_FORWARD][k][ 4]*O[ 4] + g_aiT32[TRANSFORM_FORWARD][k][ 5]*O[ 5] + + g_aiT32[TRANSFORM_FORWARD][k][ 6]*O[ 6] + g_aiT32[TRANSFORM_FORWARD][k][ 7]*O[ 7] + + g_aiT32[TRANSFORM_FORWARD][k][ 8]*O[ 8] + g_aiT32[TRANSFORM_FORWARD][k][ 9]*O[ 9] + + g_aiT32[TRANSFORM_FORWARD][k][10]*O[10] + g_aiT32[TRANSFORM_FORWARD][k][11]*O[11] + + g_aiT32[TRANSFORM_FORWARD][k][12]*O[12] + g_aiT32[TRANSFORM_FORWARD][k][13]*O[13] + + g_aiT32[TRANSFORM_FORWARD][k][14]*O[14] + g_aiT32[TRANSFORM_FORWARD][k][15]*O[15] + add)>>shift; + } + + src += 32; + dst ++; + } +} + +/** 32x32 inverse transform implemented using partial butterfly structure (1D) + * \param src input data (transform coefficients) + * \param dst output data (residual) + * \param shift specifies right shift after 1D transform + */ +Void partialButterflyInverse32(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum) +{ + Int j,k; + TCoeff E[16],O[16]; + TCoeff EE[8],EO[8]; + TCoeff EEE[4],EEO[4]; + TCoeff EEEE[2],EEEO[2]; + TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0; + + for (j=0; j>shift ); + dst[k+16] = Clip3( outputMinimum, outputMaximum, (E[15-k] - O[15-k] + add)>>shift ); + } + src ++; + dst += 32; + } +} + +/** MxN forward transform (2D) +* \param block input data (residual) +* \param coeff output data (transform coefficients) +* \param iWidth input data (width of transform) +* \param iHeight input data (height of transform) +*/ +Void xTrMxN(Int bitDepth, TCoeff *block, TCoeff *coeff, Int iWidth, Int iHeight, Bool useDST, const Int maxTrDynamicRange) +{ + static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_FORWARD]; + + const Int shift_1st = ((g_aucConvertToBit[iWidth] + 2) + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxTrDynamicRange; + const Int shift_2nd = (g_aucConvertToBit[iHeight] + 2) + TRANSFORM_MATRIX_SHIFT; + + assert(shift_1st >= 0); + assert(shift_2nd >= 0); + + TCoeff tmp[ MAX_TU_SIZE * MAX_TU_SIZE ]; + + switch (iWidth) + { + case 4: + { + if ((iHeight == 4) && useDST) // Check for DCT or DST + { + fastForwardDst( block, tmp, shift_1st ); + } + else partialButterfly4 ( block, tmp, shift_1st, iHeight ); + } + break; + + case 8: partialButterfly8 ( block, tmp, shift_1st, iHeight ); break; + case 16: partialButterfly16( block, tmp, shift_1st, iHeight ); break; + case 32: partialButterfly32( block, tmp, shift_1st, iHeight ); break; + default: + assert(0); exit (1); break; + } + + switch (iHeight) + { + case 4: + { + if ((iWidth == 4) && useDST) // Check for DCT or DST + { + fastForwardDst( tmp, coeff, shift_2nd ); + } + else partialButterfly4 ( tmp, coeff, shift_2nd, iWidth ); + } + break; + + case 8: partialButterfly8 ( tmp, coeff, shift_2nd, iWidth ); break; + case 16: partialButterfly16( tmp, coeff, shift_2nd, iWidth ); break; + case 32: partialButterfly32( tmp, coeff, shift_2nd, iWidth ); break; + default: + assert(0); exit (1); break; + } +} + + +/** MxN inverse transform (2D) +* \param coeff input data (transform coefficients) +* \param block output data (residual) +* \param iWidth input data (width of transform) +* \param iHeight input data (height of transform) +*/ +Void xITrMxN(Int bitDepth, TCoeff *coeff, TCoeff *block, Int iWidth, Int iHeight, Bool useDST, const Int maxTrDynamicRange) +{ + static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE]; + + Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2nd + Int shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxTrDynamicRange - 1) - bitDepth; + const TCoeff clipMinimum = -(1 << maxTrDynamicRange); + const TCoeff clipMaximum = (1 << maxTrDynamicRange) - 1; + + assert(shift_1st >= 0); + assert(shift_2nd >= 0); + + TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE]; + + switch (iHeight) + { + case 4: + { + if ((iWidth == 4) && useDST) // Check for DCT or DST + { + fastInverseDst( coeff, tmp, shift_1st, clipMinimum, clipMaximum); + } + else partialButterflyInverse4 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); + } + break; + + case 8: partialButterflyInverse8 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break; + case 16: partialButterflyInverse16( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break; + case 32: partialButterflyInverse32( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break; + + default: + assert(0); exit (1); break; + } + + switch (iWidth) + { + // Clipping here is not in the standard, but is used to protect the "Pel" data type into which the inverse-transformed samples will be copied + case 4: + { + if ((iHeight == 4) && useDST) // Check for DCT or DST + { + fastInverseDst( tmp, block, shift_2nd, std::numeric_limits::min(), std::numeric_limits::max() ); + } + else partialButterflyInverse4 ( tmp, block, shift_2nd, iHeight, std::numeric_limits::min(), std::numeric_limits::max()); + } + break; + + case 8: partialButterflyInverse8 ( tmp, block, shift_2nd, iHeight, std::numeric_limits::min(), std::numeric_limits::max()); break; + case 16: partialButterflyInverse16( tmp, block, shift_2nd, iHeight, std::numeric_limits::min(), std::numeric_limits::max()); break; + case 32: partialButterflyInverse32( tmp, block, shift_2nd, iHeight, std::numeric_limits::min(), std::numeric_limits::max()); break; + + default: + assert(0); exit (1); break; + } +} + + +// To minimize the distortion only. No rate is considered. +Void TComTrQuant::signBitHidingHDQ( const ComponentID compID, TCoeff* pQCoef, TCoeff* pCoef, TCoeff* deltaU, const TUEntropyCodingParameters &codingParameters ) +{ + const UInt width = codingParameters.widthInGroups << MLS_CG_LOG2_WIDTH; + const UInt height = codingParameters.heightInGroups << MLS_CG_LOG2_HEIGHT; + const UInt groupSize = 1 << MLS_CG_SIZE; + + const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]); + const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1; + + Int lastCG = -1; + Int absSum = 0 ; + Int n ; + + for( Int subSet = (width*height-1) >> MLS_CG_SIZE; subSet >= 0; subSet-- ) + { + Int subPos = subSet << MLS_CG_SIZE; + Int firstNZPosInCG=groupSize , lastNZPosInCG=-1 ; + absSum = 0 ; + + for(n = groupSize-1; n >= 0; --n ) + { + if( pQCoef[ codingParameters.scan[ n + subPos ]] ) + { + lastNZPosInCG = n; + break; + } + } + + for(n = 0; n =0 && lastCG==-1) + { + lastCG = 1 ; + } + + if( lastNZPosInCG-firstNZPosInCG>=SBH_THRESHOLD ) + { + UInt signbit = (pQCoef[codingParameters.scan[subPos+firstNZPosInCG]]>0?0:1) ; + if( signbit!=(absSum&0x1) ) //compare signbit with sum_parity + { + TCoeff curCost = std::numeric_limits::max(); + TCoeff minCostInc = std::numeric_limits::max(); + Int minPos =-1, finalChange=0, curChange=0; + + for( n = (lastCG==1?lastNZPosInCG:groupSize-1) ; n >= 0; --n ) + { + UInt blkPos = codingParameters.scan[ n+subPos ]; + if(pQCoef[ blkPos ] != 0 ) + { + if(deltaU[blkPos]>0) + { + curCost = - deltaU[blkPos]; + curChange=1 ; + } + else + { + //curChange =-1; + if(n==firstNZPosInCG && abs(pQCoef[blkPos])==1) + { + curCost = std::numeric_limits::max(); + } + else + { + curCost = deltaU[blkPos]; + curChange =-1; + } + } + } + else + { + if(n=0?0:1); + if(thisSignBit != signbit ) + { + curCost = std::numeric_limits::max(); + } + else + { + curCost = - (deltaU[blkPos]) ; + curChange = 1 ; + } + } + else + { + curCost = - (deltaU[blkPos]) ; + curChange = 1 ; + } + } + + if( curCost=0) + { + pQCoef[minPos] += finalChange ; + } + else + { + pQCoef[minPos] -= finalChange ; + } + } // Hide + } + if(lastCG==1) + { + lastCG=0 ; + } + } // TU loop + + return; +} + + +Void TComTrQuant::xQuant( TComTU &rTu, + TCoeff * pSrc, + TCoeff * pDes, +#if ADAPTIVE_QP_SELECTION + TCoeff *pArlDes, +#endif + TCoeff &uiAbsSum, + const ComponentID compID, + const QpParam &cQP ) +{ + const TComRectangle &rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + TComDataCU* pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + + TCoeff* piCoef = pSrc; + TCoeff* piQCoef = pDes; +#if ADAPTIVE_QP_SELECTION + TCoeff* piArlCCoef = pArlDes; +#endif + + const Bool useTransformSkip = pcCU->getTransformSkip(uiAbsPartIdx, compID); + + Bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ; + if ( useRDOQ && (isLuma(compID) || RDOQ_CHROMA) ) + { +#if ADAPTIVE_QP_SELECTION + xRateDistOptQuant( rTu, piCoef, pDes, pArlDes, uiAbsSum, compID, cQP ); +#else + xRateDistOptQuant( rTu, piCoef, pDes, uiAbsSum, compID, cQP ); +#endif + } + else + { + TUEntropyCodingParameters codingParameters; + getTUEntropyCodingParameters(codingParameters, rTu, compID); + + const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]); + const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1; + + TCoeff deltaU[MAX_TU_SIZE * MAX_TU_SIZE]; + + const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID); + + Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID); + assert(scalingListType < SCALING_LIST_NUM); + Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrSize-2); + + const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0)); + const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem]; + + /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be + * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the + * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller) + * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result + */ + + // Represents scaling through forward transform + Int iTransformShift = getTransformShift(toChannelType(compID), uiLog2TrSize); + if (useTransformSkip && pcCU->getSlice()->getSPS()->getUseExtendedPrecision()) + { + iTransformShift = std::max(0, iTransformShift); + } + + const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift; + // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset + +#if ADAPTIVE_QP_SELECTION + Int iQBitsC = MAX_INT; + Int iAddC = MAX_INT; + + if (m_bUseAdaptQpSelect) + { + iQBitsC = iQBits - ARL_C_PRECISION; + iAddC = 1 << (iQBitsC-1); + } +#endif + + const Int iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9); + const Int qBits8 = iQBits - 8; + + for( Int uiBlockPos = 0; uiBlockPos < uiWidth*uiHeight; uiBlockPos++ ) + { + const TCoeff iLevel = piCoef[uiBlockPos]; + const TCoeff iSign = (iLevel < 0 ? -1: 1); + + const Int64 tmpLevel = (Int64)abs(iLevel) * (enableScalingLists ? piQuantCoeff[uiBlockPos] : defaultQuantisationCoefficient); + +#if ADAPTIVE_QP_SELECTION + if( m_bUseAdaptQpSelect ) + { + piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel + iAddC ) >> iQBitsC); + } +#endif + + const TCoeff quantisedMagnitude = TCoeff((tmpLevel + iAdd ) >> iQBits); + deltaU[uiBlockPos] = (TCoeff)((tmpLevel - (quantisedMagnitude<> qBits8); + + uiAbsSum += quantisedMagnitude; + const TCoeff quantisedCoefficient = quantisedMagnitude * iSign; + + piQCoef[uiBlockPos] = Clip3( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient ); + } // for n + + if( pcCU->getSlice()->getPPS()->getSignHideFlag() ) + { + if(uiAbsSum >= 2) //this prevents TUs with only one coefficient of value 1 from being tested + { + signBitHidingHDQ( compID, piQCoef, piCoef, deltaU, codingParameters ) ; + } + } + } //if RDOQ + //return; +} + +Void TComTrQuant::xDeQuant( TComTU &rTu, + const TCoeff * pSrc, + TCoeff * pDes, + const ComponentID compID, + const QpParam &cQP ) +{ + assert(compIDgetTransformSkip(uiAbsPartIdx, compID) != 0)); + const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID); + + assert (scalingListType < SCALING_LIST_NUM); + assert ( uiWidth <= m_uiMaxTrSize ); + + // Represents scaling through forward transform + const Bool bClipTransformShiftTo0 = (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0) && pcCU->getSlice()->getSPS()->getUseExtendedPrecision(); + const Int originalTransformShift = getTransformShift(toChannelType(compID), uiLog2TrSize); + const Int iTransformShift = bClipTransformShiftTo0 ? std::max(0, originalTransformShift) : originalTransformShift; + + const Int QP_per = cQP.per; + const Int QP_rem = cQP.rem; + + const Int rightShift = (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0); + + if(enableScalingLists) + { + //from the dequantisation equation: + //iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[deQuantIdx]) + iAdd ) >> rightShift + //(sizeof(Intermediate_Int) * 8) = inputBitDepth + dequantCoefBits - rightShift + const UInt dequantCoefBits = 1 + IQUANT_SHIFT + SCALING_LIST_BITS; + const UInt targetInputBitDepth = std::min((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - dequantCoefBits)); + + const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1)); + const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1; + + Int *piDequantCoef = getDequantCoeff(scalingListType,QP_rem,uiLog2TrSize-2); + + if(rightShift > 0) + { + const Intermediate_Int iAdd = 1 << (rightShift - 1); + + for( Int n = 0; n < numSamplesInBlock; n++ ) + { + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, piQCoef[n])); + const Intermediate_Int iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[n]) + iAdd ) >> rightShift; + + piCoef[n] = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + else + { + const Int leftShift = -rightShift; + + for( Int n = 0; n < numSamplesInBlock; n++ ) + { + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, piQCoef[n])); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * piDequantCoef[n]) << leftShift; + + piCoef[n] = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + } + else + { + const Int scale = g_invQuantScales[QP_rem]; + const Int scaleBits = (IQUANT_SHIFT + 1) ; + + //from the dequantisation equation: + //iCoeffQ = Intermediate_Int((Int64(clipQCoef) * scale + iAdd) >> rightShift); + //(sizeof(Intermediate_Int) * 8) = inputBitDepth + scaleBits - rightShift + const UInt targetInputBitDepth = std::min((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - scaleBits)); + const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1)); + const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1; + + if (rightShift > 0) + { + const Intermediate_Int iAdd = 1 << (rightShift - 1); + + for( Int n = 0; n < numSamplesInBlock; n++ ) + { + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, piQCoef[n])); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale + iAdd) >> rightShift; + + piCoef[n] = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + else + { + const Int leftShift = -rightShift; + + for( Int n = 0; n < numSamplesInBlock; n++ ) + { + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, piQCoef[n])); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale) << leftShift; + + piCoef[n] = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + } +} + + +Void TComTrQuant::init( UInt uiMaxTrSize, + Bool bUseRDOQ, + Bool bUseRDOQTS, + Bool bEnc, + Bool useTransformSkipFast +#if ADAPTIVE_QP_SELECTION + , Bool bUseAdaptQpSelect +#endif + ) +{ + m_uiMaxTrSize = uiMaxTrSize; + m_bEnc = bEnc; + m_useRDOQ = bUseRDOQ; + m_useRDOQTS = bUseRDOQTS; +#if ADAPTIVE_QP_SELECTION + m_bUseAdaptQpSelect = bUseAdaptQpSelect; +#endif + m_useTransformSkipFast = useTransformSkipFast; +} + + +Void TComTrQuant::transformNxN( TComTU & rTu, + const ComponentID compID, + Pel * pcResidual, + const UInt uiStride, + TCoeff * rpcCoeff, +#if ADAPTIVE_QP_SELECTION + TCoeff * pcArlCoeff, +#endif + TCoeff & uiAbsSum, + const QpParam & cQP + ) +{ + const TComRectangle &rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + TComDataCU* pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiOrgTrDepth = rTu.GetTransformDepthRel(); + + uiAbsSum=0; + + RDPCMMode rdpcmMode = RDPCM_OFF; + rdpcmNxN( rTu, compID, pcResidual, uiStride, cQP, rpcCoeff, uiAbsSum, rdpcmMode ); + + if (rdpcmMode == RDPCM_OFF) + { + uiAbsSum = 0; + //transform and quantise + if(pcCU->getCUTransquantBypass(uiAbsPartIdx)) + { + const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID); + const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1; + + for (UInt y = 0, coefficientIndex = 0; ygetSlice()->getSPS()->getMaxTrSize() >= uiWidth) ); + + if(pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0) + { + xTransformSkip( pcResidual, uiStride, m_plTempCoeff, rTu, compID ); + } + else + { + xT( compID, rTu.useDST(compID), pcResidual, uiStride, m_plTempCoeff, uiWidth, uiHeight ); + } + +#ifdef DEBUG_TRANSFORM_AND_QUANTISE + std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between transform and quantiser\n"; + printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth); +#endif + + xQuant( rTu, m_plTempCoeff, rpcCoeff, + +#if ADAPTIVE_QP_SELECTION + pcArlCoeff, +#endif + uiAbsSum, compID, cQP ); + +#ifdef DEBUG_TRANSFORM_AND_QUANTISE + std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of quantiser\n"; + printBlock(rpcCoeff, uiWidth, uiHeight, uiWidth); +#endif + } + } + + //set the CBF + pcCU->setCbfPartRange((((uiAbsSum > 0) ? 1 : 0) << uiOrgTrDepth), compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID)); +} + + +Void TComTrQuant::invTransformNxN( TComTU &rTu, + const ComponentID compID, + Pel *pcResidual, + const UInt uiStride, + TCoeff * pcCoeff, + const QpParam &cQP + DEBUG_STRING_FN_DECLAREP(psDebug)) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const TComRectangle &rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + + if (uiWidth != uiHeight) //for intra, the TU will have been split above this level, so this condition won't be true, hence this only affects inter + { + //------------------------------------------------ + + //recurse deeper + + TComTURecurse subTURecurse(rTu, false, TComTU::VERTICAL_SPLIT, true, compID); + + do + { + //------------------ + + const UInt lineOffset = subTURecurse.GetSectionNumber() * subTURecurse.getRect(compID).height; + + Pel *subTUResidual = pcResidual + (lineOffset * uiStride); + TCoeff *subTUCoefficients = pcCoeff + (lineOffset * subTURecurse.getRect(compID).width); + + invTransformNxN(subTURecurse, compID, subTUResidual, uiStride, subTUCoefficients, cQP DEBUG_STRING_PASS_INTO(psDebug)); + + //------------------ + + } + while (subTURecurse.nextSection(rTu)); + + //------------------------------------------------ + + return; + } + +#if defined DEBUG_STRING + if (psDebug) + { + std::stringstream ss(stringstream::out); + printBlockToStream(ss, (compID==0)?"###InvTran ip Ch0: " : ((compID==1)?"###InvTran ip Ch1: ":"###InvTran ip Ch2: "), pcCoeff, uiWidth, uiHeight, uiWidth); + DEBUG_STRING_APPEND((*psDebug), ss.str()) + } +#endif + + if(pcCU->getCUTransquantBypass(uiAbsPartIdx)) + { + const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID); + const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1; + + for (UInt y = 0, coefficientIndex = 0; ygetTransformSkip(uiAbsPartIdx, compID)) + { + xITransformSkip( m_plTempCoeff, pcResidual, uiStride, rTu, compID ); + +#if defined DEBUG_STRING + if (psDebug) + { + std::stringstream ss(stringstream::out); + printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride); + (*psDebug)+=ss.str(); + (*psDebug)+="(<- was a Transform-skipped block)\n"; + } +#endif + } + else + { + xIT( compID, rTu.useDST(compID), m_plTempCoeff, pcResidual, uiStride, uiWidth, uiHeight ); + +#if defined DEBUG_STRING + if (psDebug) + { + std::stringstream ss(stringstream::out); + printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride); + (*psDebug)+=ss.str(); + (*psDebug)+="(<- was a Transformed block)\n"; + } +#endif + } + +#ifdef DEBUG_TRANSFORM_AND_QUANTISE + std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of inverse-transform\n"; + printBlock(pcResidual, uiWidth, uiHeight, uiStride); + g_debugCounter++; +#endif + } + + invRdpcmNxN( rTu, compID, pcResidual, uiStride ); +} + +Void TComTrQuant::invRecurTransformNxN( const ComponentID compID, + TComYuv *pResidual, + TComTU &rTu) +{ + if (!rTu.ProcessComponentSection(compID)) return; + + TComDataCU* pcCU = rTu.getCU(); + UInt absPartIdxTU = rTu.GetAbsPartIdxTU(); + UInt uiTrMode=rTu.GetTransformDepthRel(); + if( (pcCU->getCbf(absPartIdxTU, compID, uiTrMode) == 0) && (isLuma(compID) || !pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) ) + { + return; + } + + if( uiTrMode == pcCU->getTransformIdx( absPartIdxTU ) ) + { + const TComRectangle &tuRect = rTu.getRect(compID); + const Int uiStride = pResidual->getStride( compID ); + Pel *rpcResidual = pResidual->getAddr( compID ); + UInt uiAddr = (tuRect.x0 + uiStride*tuRect.y0); + Pel *pResi = rpcResidual + uiAddr; + TCoeff *pcCoeff = pcCU->getCoeff(compID) + rTu.getCoefficientOffset(compID); + + const QpParam cQP(*pcCU, compID); + + if(pcCU->getCbf(absPartIdxTU, compID, uiTrMode) != 0) + { + DEBUG_STRING_NEW(sTemp) +#ifdef DEBUG_STRING + std::string *psDebug=((DebugOptionList::DebugString_InvTran.getInt()&(pcCU->isIntra(absPartIdxTU)?1:(pcCU->isInter(absPartIdxTU)?2:4)))!=0) ? &sTemp : 0; +#endif + + invTransformNxN( rTu, compID, pResi, uiStride, pcCoeff, cQP DEBUG_STRING_PASS_INTO(psDebug) ); + +#ifdef DEBUG_STRING + if (psDebug != 0) + std::cout << (*psDebug); +#endif + } + + if (isChroma(compID) && (pcCU->getCrossComponentPredictionAlpha(absPartIdxTU, compID) != 0)) + { + const Pel *piResiLuma = pResidual->getAddr( COMPONENT_Y ); + const Int strideLuma = pResidual->getStride( COMPONENT_Y ); + const Int tuWidth = rTu.getRect( compID ).width; + const Int tuHeight = rTu.getRect( compID ).height; + + if(pcCU->getCbf(absPartIdxTU, COMPONENT_Y, uiTrMode) != 0) + { + pResi = rpcResidual + uiAddr; + const Pel *pResiLuma = piResiLuma + uiAddr; + + crossComponentPrediction( rTu, compID, pResiLuma, pResi, pResi, tuWidth, tuHeight, strideLuma, uiStride, uiStride, true ); + } + } + } + else + { + TComTURecurse tuRecurseChild(rTu, false); + do + { + invRecurTransformNxN( compID, pResidual, tuRecurseChild ); + } + while (tuRecurseChild.nextSection(rTu)); + } +} + +Void TComTrQuant::applyForwardRDPCM( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, const RDPCMMode mode ) +{ + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + + const Bool bLossless = pcCU->getCUTransquantBypass( uiAbsPartIdx ); + const UInt uiWidth = rTu.getRect(compID).width; + const UInt uiHeight = rTu.getRect(compID).height; + const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID); + const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1; + + Pel reconstructedResi[MAX_TU_SIZE * MAX_TU_SIZE]; + + UInt uiX = 0; + UInt uiY = 0; + + UInt &majorAxis = (mode == RDPCM_HOR) ? uiX : uiY; + UInt &minorAxis = (mode == RDPCM_HOR) ? uiY : uiX; + const UInt majorAxisLimit = (mode == RDPCM_HOR) ? uiWidth : uiHeight; + const UInt minorAxisLimit = (mode == RDPCM_HOR) ? uiHeight : uiWidth; + const UInt referenceSampleOffset = (mode == RDPCM_HOR) ? 1 : uiWidth; + + const Bool bUseHalfRoundingPoint = (mode != RDPCM_OFF); + + uiAbsSum = 0; + + for ( majorAxis = 0; majorAxis < majorAxisLimit; majorAxis++ ) + { + for ( minorAxis = 0; minorAxis < minorAxisLimit; minorAxis++ ) + { + const UInt sampleIndex = (uiY * uiWidth) + uiX; + const UInt coefficientIndex = (rotateResidual ? (uiSizeMinus1-sampleIndex) : sampleIndex); + const Pel currentSample = pcResidual[(uiY * uiStride) + uiX]; + const Pel referenceSample = ((mode != RDPCM_OFF) && (majorAxis > 0)) ? reconstructedResi[sampleIndex - referenceSampleOffset] : 0; + + const Pel encoderSideDelta = currentSample - referenceSample; + + Pel reconstructedDelta; + if ( bLossless ) + { + pcCoeff[coefficientIndex] = encoderSideDelta; + reconstructedDelta = encoderSideDelta; + } + else + { + transformSkipQuantOneSample(rTu, compID, encoderSideDelta, pcCoeff, coefficientIndex, cQP, bUseHalfRoundingPoint); + invTrSkipDeQuantOneSample (rTu, compID, pcCoeff[coefficientIndex], reconstructedDelta, cQP, coefficientIndex); + } + + uiAbsSum += abs(pcCoeff[coefficientIndex]); + + reconstructedResi[sampleIndex] = reconstructedDelta + referenceSample; + } + } +} + +Void TComTrQuant::rdpcmNxN ( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, RDPCMMode& rdpcmMode ) +{ + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + + if (!pcCU->isRDPCMEnabled(uiAbsPartIdx) || ((pcCU->getTransformSkip(uiAbsPartIdx, compID) == 0) && !pcCU->getCUTransquantBypass(uiAbsPartIdx))) + { + rdpcmMode = RDPCM_OFF; + } + else if ( pcCU->isIntra( uiAbsPartIdx ) ) + { + const ChromaFormat chFmt = pcCU->getPic()->getPicYuvOrg()->getChromaFormat(); + const ChannelType chType = toChannelType(compID); + const UInt uiChPredMode = pcCU->getIntraDir( chType, uiAbsPartIdx ); + const UInt uiChCodedMode = (uiChPredMode==DM_CHROMA_IDX && isChroma(compID)) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, chFmt)) : uiChPredMode; + const UInt uiChFinalMode = ((chFmt == CHROMA_422) && isChroma(compID)) ? g_chroma422IntraAngleMappingTable[uiChCodedMode] : uiChCodedMode; + + if (uiChFinalMode == VER_IDX || uiChFinalMode == HOR_IDX) + { + rdpcmMode = (uiChFinalMode == VER_IDX) ? RDPCM_VER : RDPCM_HOR; + applyForwardRDPCM( rTu, compID, pcResidual, uiStride, cQP, pcCoeff, uiAbsSum, rdpcmMode ); + } + else rdpcmMode = RDPCM_OFF; + } + else // not intra, need to select the best mode + { + const UInt uiWidth = rTu.getRect(compID).width; + const UInt uiHeight = rTu.getRect(compID).height; + + RDPCMMode bestMode = NUMBER_OF_RDPCM_MODES; + TCoeff bestAbsSum = std::numeric_limits::max(); + TCoeff bestCoefficients[MAX_TU_SIZE * MAX_TU_SIZE]; + + for (UInt modeIndex = 0; modeIndex < NUMBER_OF_RDPCM_MODES; modeIndex++) + { + const RDPCMMode mode = RDPCMMode(modeIndex); + + TCoeff currAbsSum = 0; + + applyForwardRDPCM( rTu, compID, pcResidual, uiStride, cQP, pcCoeff, currAbsSum, mode ); + + if (currAbsSum < bestAbsSum) + { + bestMode = mode; + bestAbsSum = currAbsSum; + if (mode != RDPCM_OFF) + { + memcpy(bestCoefficients, pcCoeff, (uiWidth * uiHeight * sizeof(TCoeff))); + } + } + } + + rdpcmMode = bestMode; + uiAbsSum = bestAbsSum; + + if (rdpcmMode != RDPCM_OFF) //the TU is re-transformed and quantised if DPCM_OFF is returned, so there is no need to preserve it here + { + memcpy(pcCoeff, bestCoefficients, (uiWidth * uiHeight * sizeof(TCoeff))); + } + } + + pcCU->setExplicitRdpcmModePartRange(rdpcmMode, compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID)); +} + +Void TComTrQuant::invRdpcmNxN( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride ) +{ + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + + if (pcCU->isRDPCMEnabled( uiAbsPartIdx ) && ((pcCU->getTransformSkip(uiAbsPartIdx, compID ) != 0) || pcCU->getCUTransquantBypass(uiAbsPartIdx))) + { + const UInt uiWidth = rTu.getRect(compID).width; + const UInt uiHeight = rTu.getRect(compID).height; + + RDPCMMode rdpcmMode = RDPCM_OFF; + + if ( pcCU->isIntra( uiAbsPartIdx ) ) + { + const ChromaFormat chFmt = pcCU->getPic()->getPicYuvRec()->getChromaFormat(); + const ChannelType chType = toChannelType(compID); + const UInt uiChPredMode = pcCU->getIntraDir( chType, uiAbsPartIdx ); + const UInt uiChCodedMode = (uiChPredMode==DM_CHROMA_IDX && isChroma(compID)) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, chFmt)) : uiChPredMode; + const UInt uiChFinalMode = ((chFmt == CHROMA_422) && isChroma(compID)) ? g_chroma422IntraAngleMappingTable[uiChCodedMode] : uiChCodedMode; + + if (uiChFinalMode == VER_IDX || uiChFinalMode == HOR_IDX) + { + rdpcmMode = (uiChFinalMode == VER_IDX) ? RDPCM_VER : RDPCM_HOR; + } + } + else // not intra case + { + rdpcmMode = RDPCMMode(pcCU->getExplicitRdpcmMode( compID, uiAbsPartIdx )); + } + + if (rdpcmMode == RDPCM_VER) + { + pcResidual += uiStride; //start from row 1 + + for( UInt uiY = 1; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pcResidual[ uiX ] = pcResidual[ uiX ] + pcResidual [ (Int)uiX - (Int)uiStride ]; + } + pcResidual += uiStride; + } + } + else if (rdpcmMode == RDPCM_HOR) + { + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 1; uiX < uiWidth; uiX++ ) + { + pcResidual[ uiX ] = pcResidual[ uiX ] + pcResidual [ (Int)uiX-1 ]; + } + pcResidual += uiStride; + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Logical transform +// ------------------------------------------------------------------------------------------------ + +/** Wrapper function between HM interface and core NxN forward transform (2D) + * \param piBlkResi input data (residual) + * \param psCoeff output data (transform coefficients) + * \param uiStride stride of input residual data + * \param iSize transform size (iSize x iSize) + * \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only + */ +Void TComTrQuant::xT( const ComponentID compID, Bool useDST, Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, Int iWidth, Int iHeight ) +{ +#if MATRIX_MULT + if( iWidth == iHeight) + { + xTr(g_bitDepth[toChannelType(compID)], piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]); + return; + } +#endif + + TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ]; + TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ]; + + for (Int y = 0; y < iHeight; y++) + for (Int x = 0; x < iWidth; x++) + { + block[(y * iWidth) + x] = piBlkResi[(y * uiStride) + x]; + } + + xTrMxN( g_bitDepth[toChannelType(compID)], block, coeff, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] ); + + memcpy(psCoeff, coeff, (iWidth * iHeight * sizeof(TCoeff))); +} + +/** Wrapper function between HM interface and core NxN inverse transform (2D) + * \param plCoef input data (transform coefficients) + * \param pResidual output data (residual) + * \param uiStride stride of input residual data + * \param iSize transform size (iSize x iSize) + * \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only + */ +Void TComTrQuant::xIT( const ComponentID compID, Bool useDST, TCoeff* plCoef, Pel* pResidual, UInt uiStride, Int iWidth, Int iHeight ) +{ +#if MATRIX_MULT + if( iWidth == iHeight ) + { +#if O0043_BEST_EFFORT_DECODING + xITr(g_bitDepthInStream[toChannelType(compID)], plCoef, pResidual, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]); +#else + xITr(g_bitDepth[toChannelType(compID)], plCoef, pResidual, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]); +#endif + return; + } +#endif + + TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ]; + TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ]; + + memcpy(coeff, plCoef, (iWidth * iHeight * sizeof(TCoeff))); + +#if O0043_BEST_EFFORT_DECODING + xITrMxN( g_bitDepthInStream[toChannelType(compID)], coeff, block, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] ); +#else + xITrMxN( g_bitDepth[toChannelType(compID)], coeff, block, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] ); +#endif + + for (Int y = 0; y < iHeight; y++) + for (Int x = 0; x < iWidth; x++) + { + pResidual[(y * uiStride) + x] = Pel(block[(y * iWidth) + x]); + } +} + +/** Wrapper function between HM interface and core 4x4 transform skipping + * \param piBlkResi input data (residual) + * \param psCoeff output data (transform coefficients) + * \param uiStride stride of input residual data + * \param iSize transform size (iSize x iSize) + */ +Void TComTrQuant::xTransformSkip( Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, TComTU &rTu, const ComponentID component ) +{ + const TComRectangle &rect = rTu.getRect(component); + const Int width = rect.width; + const Int height = rect.height; + + Int iTransformShift = getTransformShift(toChannelType(component), rTu.GetEquivalentLog2TrSize(component)); + if (rTu.getCU()->getSlice()->getSPS()->getUseExtendedPrecision()) + { + iTransformShift = std::max(0, iTransformShift); + } + + const Bool rotateResidual = rTu.isNonTransformedResidualRotated(component); + const UInt uiSizeMinus1 = (width * height) - 1; + + if (iTransformShift >= 0) + { + for (UInt y = 0, coefficientIndex = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++, coefficientIndex++) + { + psCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = TCoeff(piBlkResi[(y * uiStride) + x]) << iTransformShift; + } + } + } + else //for very high bit depths + { + iTransformShift = -iTransformShift; + const TCoeff offset = 1 << (iTransformShift - 1); + + for (UInt y = 0, coefficientIndex = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++, coefficientIndex++) + { + psCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = (TCoeff(piBlkResi[(y * uiStride) + x]) + offset) >> iTransformShift; + } + } + } +} + +/** Wrapper function between HM interface and core NxN transform skipping + * \param plCoef input data (coefficients) + * \param pResidual output data (residual) + * \param uiStride stride of input residual data + * \param iSize transform size (iSize x iSize) + */ +Void TComTrQuant::xITransformSkip( TCoeff* plCoef, Pel* pResidual, UInt uiStride, TComTU &rTu, const ComponentID component ) +{ + const TComRectangle &rect = rTu.getRect(component); + const Int width = rect.width; + const Int height = rect.height; + + Int iTransformShift = getTransformShift(toChannelType(component), rTu.GetEquivalentLog2TrSize(component)); + if (rTu.getCU()->getSlice()->getSPS()->getUseExtendedPrecision()) + { + iTransformShift = std::max(0, iTransformShift); + } + + const Bool rotateResidual = rTu.isNonTransformedResidualRotated(component); + const UInt uiSizeMinus1 = (width * height) - 1; + + if (iTransformShift >= 0) + { + const TCoeff offset = iTransformShift==0 ? 0 : (1 << (iTransformShift - 1)); + + for (UInt y = 0, coefficientIndex = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++, coefficientIndex++) + { + pResidual[(y * uiStride) + x] = Pel((plCoef[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] + offset) >> iTransformShift); + } + } + } + else //for very high bit depths + { + iTransformShift = -iTransformShift; + + for (UInt y = 0, coefficientIndex = 0; y < height; y++) + { + for (UInt x = 0; x < width; x++, coefficientIndex++) + { + pResidual[(y * uiStride) + x] = Pel(plCoef[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] << iTransformShift); + } + } + } +} + +/** RDOQ with CABAC + * \param pcCU pointer to coding unit structure + * \param plSrcCoeff pointer to input buffer + * \param piDstCoeff reference to pointer to output buffer + * \param uiWidth block width + * \param uiHeight block height + * \param uiAbsSum reference to absolute sum of quantized transform coefficient + * \param eTType plane type / luminance or chrominance + * \param uiAbsPartIdx absolute partition index + * \returns Void + * Rate distortion optimized quantization for entropy + * coding engines using probability models like CABAC + */ +Void TComTrQuant::xRateDistOptQuant ( TComTU &rTu, + TCoeff * plSrcCoeff, + TCoeff * piDstCoeff, +#if ADAPTIVE_QP_SELECTION + TCoeff * piArlDstCoeff, +#endif + TCoeff &uiAbsSum, + const ComponentID compID, + const QpParam &cQP ) +{ + const TComRectangle & rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + TComDataCU * pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const ChannelType channelType = toChannelType(compID); + const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID); + + const Bool extendedPrecision = pcCU->getSlice()->getSPS()->getUseExtendedPrecision(); + + /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be + * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the + * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller) + * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result + */ + + // Represents scaling through forward transform + Int iTransformShift = getTransformShift(channelType, uiLog2TrSize); + if ((pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0) && pcCU->getSlice()->getSPS()->getUseExtendedPrecision()) + { + iTransformShift = std::max(0, iTransformShift); + } + + const Bool bUseGolombRiceParameterAdaptation = pcCU->getSlice()->getSPS()->getUseGolombRiceParameterAdaptation(); + const UInt initialGolombRiceParameter = m_pcEstBitsSbac->golombRiceAdaptationStatistics[rTu.getGolombRiceStatisticsIndex(compID)] / RExt__GOLOMB_RICE_INCREMENT_DIVISOR; + UInt uiGoRiceParam = initialGolombRiceParameter; + Double d64BlockUncodedCost = 0; + const UInt uiLog2BlockWidth = g_aucConvertToBit[ uiWidth ] + 2; + const UInt uiLog2BlockHeight = g_aucConvertToBit[ uiHeight ] + 2; + const UInt uiMaxNumCoeff = uiWidth * uiHeight; + assert(compIDgetPredictionMode(uiAbsPartIdx), compID); + assert(scalingListType < SCALING_LIST_NUM); + +#if ADAPTIVE_QP_SELECTION + memset(piArlDstCoeff, 0, sizeof(TCoeff) * uiMaxNumCoeff); +#endif + + Double pdCostCoeff [ MAX_TU_SIZE * MAX_TU_SIZE ]; + Double pdCostSig [ MAX_TU_SIZE * MAX_TU_SIZE ]; + Double pdCostCoeff0[ MAX_TU_SIZE * MAX_TU_SIZE ]; + memset( pdCostCoeff, 0, sizeof(Double) * uiMaxNumCoeff ); + memset( pdCostSig, 0, sizeof(Double) * uiMaxNumCoeff ); + Int rateIncUp [ MAX_TU_SIZE * MAX_TU_SIZE ]; + Int rateIncDown [ MAX_TU_SIZE * MAX_TU_SIZE ]; + Int sigRateDelta[ MAX_TU_SIZE * MAX_TU_SIZE ]; + TCoeff deltaU [ MAX_TU_SIZE * MAX_TU_SIZE ]; + memset( rateIncUp, 0, sizeof(Int ) * uiMaxNumCoeff ); + memset( rateIncDown, 0, sizeof(Int ) * uiMaxNumCoeff ); + memset( sigRateDelta, 0, sizeof(Int ) * uiMaxNumCoeff ); + memset( deltaU, 0, sizeof(TCoeff) * uiMaxNumCoeff ); + + const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift; // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits + const Double *const pdErrScale = getErrScaleCoeff(scalingListType, (uiLog2TrSize-2), cQP.rem); + const Int *const piQCoef = getQuantCoeff(scalingListType, cQP.rem, (uiLog2TrSize-2)); + + const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0)); + const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem]; + const Double defaultErrorScale = getErrScaleCoeffNoScalingList(scalingListType, (uiLog2TrSize-2), cQP.rem); + + const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]); + const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1; + +#if ADAPTIVE_QP_SELECTION + Int iQBitsC = iQBits - ARL_C_PRECISION; + Int iAddC = 1 << (iQBitsC-1); +#endif + + TUEntropyCodingParameters codingParameters; + getTUEntropyCodingParameters(codingParameters, rTu, compID); + const UInt uiCGSize = (1 << MLS_CG_SIZE); + + Double pdCostCoeffGroupSig[ MLS_GRP_NUM ]; + UInt uiSigCoeffGroupFlag[ MLS_GRP_NUM ]; + Int iCGLastScanPos = -1; + + UInt uiCtxSet = 0; + Int c1 = 1; + Int c2 = 0; + Double d64BaseCost = 0; + Int iLastScanPos = -1; + + UInt c1Idx = 0; + UInt c2Idx = 0; + Int baseLevel; + + memset( pdCostCoeffGroupSig, 0, sizeof(Double) * MLS_GRP_NUM ); + memset( uiSigCoeffGroupFlag, 0, sizeof(UInt) * MLS_GRP_NUM ); + + UInt uiCGNum = uiWidth * uiHeight >> MLS_CG_SIZE; + Int iScanPos; + coeffGroupRDStats rdStats; + + const UInt significanceMapContextOffset = getSignificanceMapContextOffset(compID); + + for (Int iCGScanPos = uiCGNum-1; iCGScanPos >= 0; iCGScanPos--) + { + UInt uiCGBlkPos = codingParameters.scanCG[ iCGScanPos ]; + UInt uiCGPosY = uiCGBlkPos / codingParameters.widthInGroups; + UInt uiCGPosX = uiCGBlkPos - (uiCGPosY * codingParameters.widthInGroups); + + memset( &rdStats, 0, sizeof (coeffGroupRDStats)); + + const Int patternSigCtx = TComTrQuant::calcPatternSigCtx(uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups); + + for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--) + { + iScanPos = iCGScanPos*uiCGSize + iScanPosinCG; + //===== quantization ===== + UInt uiBlkPos = codingParameters.scan[iScanPos]; + // set coeff + + const Int quantisationCoefficient = (enableScalingLists) ? piQCoef [uiBlkPos] : defaultQuantisationCoefficient; + const Double errorScale = (enableScalingLists) ? pdErrScale[uiBlkPos] : defaultErrorScale; + + const Int64 tmpLevel = Int64(abs(plSrcCoeff[ uiBlkPos ])) * quantisationCoefficient; + + const Intermediate_Int lLevelDouble = (Intermediate_Int)min(tmpLevel, MAX_INTERMEDIATE_INT - (Intermediate_Int(1) << (iQBits - 1))); + +#if ADAPTIVE_QP_SELECTION + if( m_bUseAdaptQpSelect ) + { + piArlDstCoeff[uiBlkPos] = (TCoeff)(( lLevelDouble + iAddC) >> iQBitsC ); + } +#endif + const UInt uiMaxAbsLevel = std::min(UInt(entropyCodingMaximum), UInt((lLevelDouble + (Intermediate_Int(1) << (iQBits - 1))) >> iQBits)); + + const Double dErr = Double( lLevelDouble ); + pdCostCoeff0[ iScanPos ] = dErr * dErr * errorScale; + d64BlockUncodedCost += pdCostCoeff0[ iScanPos ]; + piDstCoeff[ uiBlkPos ] = uiMaxAbsLevel; + + if ( uiMaxAbsLevel > 0 && iLastScanPos < 0 ) + { + iLastScanPos = iScanPos; + uiCtxSet = getContextSetIndex(compID, (iScanPos >> MLS_CG_SIZE), 0); + iCGLastScanPos = iCGScanPos; + } + + if ( iLastScanPos >= 0 ) + { + //===== coefficient level estimation ===== + UInt uiLevel; + UInt uiOneCtx = (NUM_ONE_FLAG_CTX_PER_SET * uiCtxSet) + c1; + UInt uiAbsCtx = (NUM_ABS_FLAG_CTX_PER_SET * uiCtxSet) + c2; + + if( iScanPos == iLastScanPos ) + { + uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ], + lLevelDouble, uiMaxAbsLevel, significanceMapContextOffset, uiOneCtx, uiAbsCtx, uiGoRiceParam, + c1Idx, c2Idx, iQBits, errorScale, 1, extendedPrecision, channelType + ); + } + else + { + UShort uiCtxSig = significanceMapContextOffset + getSigCtxInc( patternSigCtx, codingParameters, iScanPos, uiLog2BlockWidth, uiLog2BlockHeight, channelType ); + + uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ], + lLevelDouble, uiMaxAbsLevel, uiCtxSig, uiOneCtx, uiAbsCtx, uiGoRiceParam, + c1Idx, c2Idx, iQBits, errorScale, 0, extendedPrecision, channelType + ); + + sigRateDelta[ uiBlkPos ] = m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 1 ] - m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 0 ]; + } + + deltaU[ uiBlkPos ] = TCoeff((lLevelDouble - (Intermediate_Int(uiLevel) << iQBits)) >> (iQBits-8)); + + if( uiLevel > 0 ) + { + Int rateNow = xGetICRate( uiLevel, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType ); + rateIncUp [ uiBlkPos ] = xGetICRate( uiLevel+1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType ) - rateNow; + rateIncDown [ uiBlkPos ] = xGetICRate( uiLevel-1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType ) - rateNow; + } + else // uiLevel == 0 + { + rateIncUp [ uiBlkPos ] = m_pcEstBitsSbac->m_greaterOneBits[ uiOneCtx ][ 0 ]; + } + piDstCoeff[ uiBlkPos ] = uiLevel; + d64BaseCost += pdCostCoeff [ iScanPos ]; + + baseLevel = (c1Idx < C1FLAG_NUMBER) ? (2 + (c2Idx < C2FLAG_NUMBER)) : 1; + if( uiLevel >= baseLevel ) + { + if (uiLevel > 3*(1<((uiGoRiceParam + 1), 4)); + } + } + if ( uiLevel >= 1) + { + c1Idx ++; + } + + //===== update bin model ===== + if( uiLevel > 1 ) + { + c1 = 0; + c2 += (c2 < 2); + c2Idx ++; + } + else if( (c1 < 3) && (c1 > 0) && uiLevel) + { + c1++; + } + + //===== context set update ===== + if( ( iScanPos % uiCGSize == 0 ) && ( iScanPos > 0 ) ) + { + uiCtxSet = getContextSetIndex(compID, ((iScanPos - 1) >> MLS_CG_SIZE), (c1 == 0)); //(iScanPos - 1) because we do this **before** entering the final group + c1 = 1; + c2 = 0; + c1Idx = 0; + c2Idx = 0; + uiGoRiceParam = initialGolombRiceParameter; + } + } + else + { + d64BaseCost += pdCostCoeff0[ iScanPos ]; + } + rdStats.d64SigCost += pdCostSig[ iScanPos ]; + if (iScanPosinCG == 0 ) + { + rdStats.d64SigCost_0 = pdCostSig[ iScanPos ]; + } + if (piDstCoeff[ uiBlkPos ] ) + { + uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1; + rdStats.d64CodedLevelandDist += pdCostCoeff[ iScanPos ] - pdCostSig[ iScanPos ]; + rdStats.d64UncodedDist += pdCostCoeff0[ iScanPos ]; + if ( iScanPosinCG != 0 ) + { + rdStats.iNNZbeforePos0++; + } + } + } //end for (iScanPosinCG) + + if (iCGLastScanPos >= 0) + { + if( iCGScanPos ) + { + if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0) + { + UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups ); + d64BaseCost += xGetRateSigCoeffGroup(0, uiCtxSig) - rdStats.d64SigCost;; + pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig); + } + else + { + if (iCGScanPos < iCGLastScanPos) //skip the last coefficient group, which will be handled together with last position below. + { + if ( rdStats.iNNZbeforePos0 == 0 ) + { + d64BaseCost -= rdStats.d64SigCost_0; + rdStats.d64SigCost -= rdStats.d64SigCost_0; + } + // rd-cost if SigCoeffGroupFlag = 0, initialization + Double d64CostZeroCG = d64BaseCost; + + // add SigCoeffGroupFlag cost to total cost + UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups ); + + if (iCGScanPos < iCGLastScanPos) + { + d64BaseCost += xGetRateSigCoeffGroup(1, uiCtxSig); + d64CostZeroCG += xGetRateSigCoeffGroup(0, uiCtxSig); + pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(1, uiCtxSig); + } + + // try to convert the current coeff group from non-zero to all-zero + d64CostZeroCG += rdStats.d64UncodedDist; // distortion for resetting non-zero levels to zero levels + d64CostZeroCG -= rdStats.d64CodedLevelandDist; // distortion and level cost for keeping all non-zero levels + d64CostZeroCG -= rdStats.d64SigCost; // sig cost for all coeffs, including zero levels and non-zerl levels + + // if we can save cost, change this block to all-zero block + if ( d64CostZeroCG < d64BaseCost ) + { + uiSigCoeffGroupFlag[ uiCGBlkPos ] = 0; + d64BaseCost = d64CostZeroCG; + if (iCGScanPos < iCGLastScanPos) + { + pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig); + } + // reset coeffs to 0 in this block + for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--) + { + iScanPos = iCGScanPos*uiCGSize + iScanPosinCG; + UInt uiBlkPos = codingParameters.scan[ iScanPos ]; + + if (piDstCoeff[ uiBlkPos ]) + { + piDstCoeff [ uiBlkPos ] = 0; + pdCostCoeff[ iScanPos ] = pdCostCoeff0[ iScanPos ]; + pdCostSig [ iScanPos ] = 0; + } + } + } // end if ( d64CostAllZeros < d64BaseCost ) + } + } // end if if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0) + } + else + { + uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1; + } + } + } //end for (iCGScanPos) + + //===== estimate last position ===== + if ( iLastScanPos < 0 ) + { + return; + } + + Double d64BestCost = 0; + Int ui16CtxCbf = 0; + Int iBestLastIdxP1 = 0; + if( !pcCU->isIntra( uiAbsPartIdx ) && isLuma(compID) && pcCU->getTransformIdx( uiAbsPartIdx ) == 0 ) + { + ui16CtxCbf = 0; + d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 0 ] ); + d64BaseCost += xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 1 ] ); + } + else + { + ui16CtxCbf = pcCU->getCtxQtCbf( rTu, channelType ); + ui16CtxCbf += getCBFContextOffset(compID); + d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 0 ] ); + d64BaseCost += xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 1 ] ); + } + + + Bool bFoundLast = false; + for (Int iCGScanPos = iCGLastScanPos; iCGScanPos >= 0; iCGScanPos--) + { + UInt uiCGBlkPos = codingParameters.scanCG[ iCGScanPos ]; + + d64BaseCost -= pdCostCoeffGroupSig [ iCGScanPos ]; + if (uiSigCoeffGroupFlag[ uiCGBlkPos ]) + { + for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--) + { + iScanPos = iCGScanPos*uiCGSize + iScanPosinCG; + + if (iScanPos > iLastScanPos) continue; + UInt uiBlkPos = codingParameters.scan[iScanPos]; + + if( piDstCoeff[ uiBlkPos ] ) + { + UInt uiPosY = uiBlkPos >> uiLog2BlockWidth; + UInt uiPosX = uiBlkPos - ( uiPosY << uiLog2BlockWidth ); + + Double d64CostLast= codingParameters.scanType == SCAN_VER ? xGetRateLast( uiPosY, uiPosX, compID ) : xGetRateLast( uiPosX, uiPosY, compID ); + Double totalCost = d64BaseCost + d64CostLast - pdCostSig[ iScanPos ]; + + if( totalCost < d64BestCost ) + { + iBestLastIdxP1 = iScanPos + 1; + d64BestCost = totalCost; + } + if( piDstCoeff[ uiBlkPos ] > 1 ) + { + bFoundLast = true; + break; + } + d64BaseCost -= pdCostCoeff[ iScanPos ]; + d64BaseCost += pdCostCoeff0[ iScanPos ]; + } + else + { + d64BaseCost -= pdCostSig[ iScanPos ]; + } + } //end for + if (bFoundLast) + { + break; + } + } // end if (uiSigCoeffGroupFlag[ uiCGBlkPos ]) + } // end for + + + for ( Int scanPos = 0; scanPos < iBestLastIdxP1; scanPos++ ) + { + Int blkPos = codingParameters.scan[ scanPos ]; + TCoeff level = piDstCoeff[ blkPos ]; + uiAbsSum += level; + piDstCoeff[ blkPos ] = ( plSrcCoeff[ blkPos ] < 0 ) ? -level : level; + } + + //===== clean uncoded coefficients ===== + for ( Int scanPos = iBestLastIdxP1; scanPos <= iLastScanPos; scanPos++ ) + { + piDstCoeff[ codingParameters.scan[ scanPos ] ] = 0; + } + + + if( pcCU->getSlice()->getPPS()->getSignHideFlag() && uiAbsSum>=2) + { + const Double inverseQuantScale = Double(g_invQuantScales[cQP.rem]); + Int64 rdFactor = (Int64)(inverseQuantScale * inverseQuantScale * (1 << (2 * cQP.per)) + / m_dLambda / 16 / (1 << (2 * DISTORTION_PRECISION_ADJUSTMENT(g_bitDepth[channelType] - 8))) + + 0.5); + + Int lastCG = -1; + Int absSum = 0 ; + Int n ; + + for( Int subSet = (uiWidth*uiHeight-1) >> MLS_CG_SIZE; subSet >= 0; subSet-- ) + { + Int subPos = subSet << MLS_CG_SIZE; + Int firstNZPosInCG=uiCGSize , lastNZPosInCG=-1 ; + absSum = 0 ; + + for(n = uiCGSize-1; n >= 0; --n ) + { + if( piDstCoeff[ codingParameters.scan[ n + subPos ]] ) + { + lastNZPosInCG = n; + break; + } + } + + for(n = 0; n =0 && lastCG==-1) + { + lastCG = 1; + } + + if( lastNZPosInCG-firstNZPosInCG>=SBH_THRESHOLD ) + { + UInt signbit = (piDstCoeff[codingParameters.scan[subPos+firstNZPosInCG]]>0?0:1); + if( signbit!=(absSum&0x1) ) // hide but need tune + { + // calculate the cost + Int64 minCostInc = MAX_INT64, curCost = MAX_INT64; + Int minPos = -1, finalChange = 0, curChange = 0; + + for( n = (lastCG==1?lastNZPosInCG:uiCGSize-1) ; n >= 0; --n ) + { + UInt uiBlkPos = codingParameters.scan[ n + subPos ]; + if(piDstCoeff[ uiBlkPos ] != 0 ) + { + Int64 costUp = rdFactor * ( - deltaU[uiBlkPos] ) + rateIncUp[uiBlkPos]; + Int64 costDown = rdFactor * ( deltaU[uiBlkPos] ) + rateIncDown[uiBlkPos] + - ((abs(piDstCoeff[uiBlkPos]) == 1) ? sigRateDelta[uiBlkPos] : 0); + + if(lastCG==1 && lastNZPosInCG==n && abs(piDstCoeff[uiBlkPos])==1) + { + costDown -= (4<<15); + } + + if(costUp=0?0:1); + if(thissignbit != signbit ) + { + curCost = MAX_INT64; + } + } + } + + if( curCost=0) + { + piDstCoeff[minPos] += finalChange ; + } + else + { + piDstCoeff[minPos] -= finalChange ; + } + } + } + + if(lastCG==1) + { + lastCG=0 ; + } + } + } +} + + +/** Pattern decision for context derivation process of significant_coeff_flag + * \param sigCoeffGroupFlag pointer to prior coded significant coeff group + * \param uiCGPosX column of current coefficient group + * \param uiCGPosY row of current coefficient group + * \param width width of the block + * \param height height of the block + * \returns pattern for current coefficient group + */ +Int TComTrQuant::calcPatternSigCtx( const UInt* sigCoeffGroupFlag, UInt uiCGPosX, UInt uiCGPosY, UInt widthInGroups, UInt heightInGroups ) +{ + if ((widthInGroups <= 1) && (heightInGroups <= 1)) return 0; + + const Bool rightAvailable = uiCGPosX < (widthInGroups - 1); + const Bool belowAvailable = uiCGPosY < (heightInGroups - 1); + + UInt sigRight = 0; + UInt sigLower = 0; + + if (rightAvailable) sigRight = ((sigCoeffGroupFlag[ (uiCGPosY * widthInGroups) + uiCGPosX + 1 ] != 0) ? 1 : 0); + if (belowAvailable) sigLower = ((sigCoeffGroupFlag[ (uiCGPosY + 1) * widthInGroups + uiCGPosX ] != 0) ? 1 : 0); + + return sigRight + (sigLower << 1); +} + + +/** Context derivation process of coeff_abs_significant_flag + * \param patternSigCtx pattern for current coefficient group + * \param codingParameters coding parmeters for the TU (includes the scan) + * \param scanPosition current position in scan order + * \param log2BlockWidth log2 width of the block + * \param log2BlockHeight log2 height of the block + * \param ChannelType channel type (CHANNEL_TYPE_LUMA/CHROMA) + * \returns ctxInc for current scan position + */ +Int TComTrQuant::getSigCtxInc ( Int patternSigCtx, + const TUEntropyCodingParameters &codingParameters, + const Int scanPosition, + const Int log2BlockWidth, + const Int log2BlockHeight, + const ChannelType chanType) +{ + if (codingParameters.firstSignificanceMapContext == significanceMapContextSetStart[chanType][CONTEXT_TYPE_SINGLE]) + { + //single context mode + return significanceMapContextSetStart[chanType][CONTEXT_TYPE_SINGLE]; + } + + const UInt rasterPosition = codingParameters.scan[scanPosition]; + const UInt posY = rasterPosition >> log2BlockWidth; + const UInt posX = rasterPosition - (posY << log2BlockWidth); + + if ((posX + posY) == 0) return 0; //special case for the DC context variable + + Int offset = MAX_INT; + + if ((log2BlockWidth == 2) && (log2BlockHeight == 2)) //4x4 + { + offset = ctxIndMap4x4[ (4 * posY) + posX ]; + } + else + { + Int cnt = 0; + + switch (patternSigCtx) + { + //------------------ + + case 0: //neither neighbouring group is significant + { + const Int posXinSubset = posX & ((1 << MLS_CG_LOG2_WIDTH) - 1); + const Int posYinSubset = posY & ((1 << MLS_CG_LOG2_HEIGHT) - 1); + const Int posTotalInSubset = posXinSubset + posYinSubset; + + //first N coefficients in scan order use 2; the next few use 1; the rest use 0. + const UInt context1Threshold = NEIGHBOURHOOD_00_CONTEXT_1_THRESHOLD_4x4; + const UInt context2Threshold = NEIGHBOURHOOD_00_CONTEXT_2_THRESHOLD_4x4; + + cnt = (posTotalInSubset >= context1Threshold) ? 0 : ((posTotalInSubset >= context2Threshold) ? 1 : 2); + } + break; + + //------------------ + + case 1: //right group is significant, below is not + { + const Int posYinSubset = posY & ((1 << MLS_CG_LOG2_HEIGHT) - 1); + const Int groupHeight = 1 << MLS_CG_LOG2_HEIGHT; + + cnt = (posYinSubset >= (groupHeight >> 1)) ? 0 : ((posYinSubset >= (groupHeight >> 2)) ? 1 : 2); //top quarter uses 2; second-from-top quarter uses 1; bottom half uses 0 + } + break; + + //------------------ + + case 2: //below group is significant, right is not + { + const Int posXinSubset = posX & ((1 << MLS_CG_LOG2_WIDTH) - 1); + const Int groupWidth = 1 << MLS_CG_LOG2_WIDTH; + + cnt = (posXinSubset >= (groupWidth >> 1)) ? 0 : ((posXinSubset >= (groupWidth >> 2)) ? 1 : 2); //left quarter uses 2; second-from-left quarter uses 1; right half uses 0 + } + break; + + //------------------ + + case 3: //both neighbouring groups are significant + { + cnt = 2; + } + break; + + //------------------ + + default: + std::cerr << "ERROR: Invalid patternSigCtx \"" << Int(patternSigCtx) << "\" in getSigCtxInc" << std::endl; + exit(1); + break; + } + + //------------------------------------------------ + + const Bool notFirstGroup = ((posX >> MLS_CG_LOG2_WIDTH) + (posY >> MLS_CG_LOG2_HEIGHT)) > 0; + + offset = (notFirstGroup ? notFirstGroupNeighbourhoodContextOffset[chanType] : 0) + cnt; + } + + return codingParameters.firstSignificanceMapContext + offset; +} + + +/** Get the best level in RD sense + * \param rd64CodedCost reference to coded cost + * \param rd64CodedCost0 reference to cost when coefficient is 0 + * \param rd64CodedCostSig reference to cost of significant coefficient + * \param lLevelDouble reference to unscaled quantized level + * \param uiMaxAbsLevel scaled quantized level + * \param ui16CtxNumSig current ctxInc for coeff_abs_significant_flag + * \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC) + * \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC) + * \param ui16AbsGoRice current Rice parameter for coeff_abs_level_minus3 + * \param iQBits quantization step size + * \param dTemp correction factor + * \param bLast indicates if the coefficient is the last significant + * \returns best quantized transform level for given scan position + * This method calculates the best quantized transform level for a given scan position. + */ +__inline UInt TComTrQuant::xGetCodedLevel ( Double& rd64CodedCost, + Double& rd64CodedCost0, + Double& rd64CodedCostSig, + Intermediate_Int lLevelDouble, + UInt uiMaxAbsLevel, + UShort ui16CtxNumSig, + UShort ui16CtxNumOne, + UShort ui16CtxNumAbs, + UShort ui16AbsGoRice, + UInt c1Idx, + UInt c2Idx, + Int iQBits, + Double errorScale, + Bool bLast, + Bool useLimitedPrefixLength, + ChannelType channelType + ) const +{ + Double dCurrCostSig = 0; + UInt uiBestAbsLevel = 0; + + if( !bLast && uiMaxAbsLevel < 3 ) + { + rd64CodedCostSig = xGetRateSigCoef( 0, ui16CtxNumSig ); + rd64CodedCost = rd64CodedCost0 + rd64CodedCostSig; + if( uiMaxAbsLevel == 0 ) + { + return uiBestAbsLevel; + } + } + else + { + rd64CodedCost = MAX_DOUBLE; + } + + if( !bLast ) + { + dCurrCostSig = xGetRateSigCoef( 1, ui16CtxNumSig ); + } + + UInt uiMinAbsLevel = ( uiMaxAbsLevel > 1 ? uiMaxAbsLevel - 1 : 1 ); + for( Int uiAbsLevel = uiMaxAbsLevel; uiAbsLevel >= uiMinAbsLevel ; uiAbsLevel-- ) + { + Double dErr = Double( lLevelDouble - ( Intermediate_Int(uiAbsLevel) << iQBits ) ); + Double dCurrCost = dErr * dErr * errorScale + xGetICost( xGetICRate( uiAbsLevel, ui16CtxNumOne, ui16CtxNumAbs, ui16AbsGoRice, c1Idx, c2Idx, useLimitedPrefixLength, channelType ) ); + dCurrCost += dCurrCostSig; + + if( dCurrCost < rd64CodedCost ) + { + uiBestAbsLevel = uiAbsLevel; + rd64CodedCost = dCurrCost; + rd64CodedCostSig = dCurrCostSig; + } + } + + return uiBestAbsLevel; +} + +/** Calculates the cost for specific absolute transform level + * \param uiAbsLevel scaled quantized level + * \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC) + * \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC) + * \param ui16AbsGoRice Rice parameter for coeff_abs_level_minus3 + * \returns cost of given absolute transform level + */ +__inline Int TComTrQuant::xGetICRate ( UInt uiAbsLevel, + UShort ui16CtxNumOne, + UShort ui16CtxNumAbs, + UShort ui16AbsGoRice, + UInt c1Idx, + UInt c2Idx, + Bool useLimitedPrefixLength, + ChannelType channelType + ) const +{ + Int iRate = Int(xGetIEPRate()); // cost of sign bit + UInt baseLevel = (c1Idx < C1FLAG_NUMBER) ? (2 + (c2Idx < C2FLAG_NUMBER)) : 1; + + if ( uiAbsLevel >= baseLevel ) + { + UInt symbol = uiAbsLevel - baseLevel; + UInt length; + if (symbol < (COEF_REMAIN_BIN_REDUCTION << ui16AbsGoRice)) + { + length = symbol>>ui16AbsGoRice; + iRate += (length+1+ui16AbsGoRice)<< 15; + } + else if (useLimitedPrefixLength) + { + const UInt maximumPrefixLength = (32 - (COEF_REMAIN_BIN_REDUCTION + g_maxTrDynamicRange[channelType])); + + UInt prefixLength = 0; + UInt suffix = (symbol >> ui16AbsGoRice) - COEF_REMAIN_BIN_REDUCTION; + + while ((prefixLength < maximumPrefixLength) && (suffix > ((2 << prefixLength) - 2))) + { + prefixLength++; + } + + const UInt suffixLength = (prefixLength == maximumPrefixLength) ? (g_maxTrDynamicRange[channelType] - ui16AbsGoRice) : (prefixLength + 1/*separator*/); + + iRate += (COEF_REMAIN_BIN_REDUCTION + prefixLength + suffixLength + ui16AbsGoRice) << 15; + } + else + { + length = ui16AbsGoRice; + symbol = symbol - ( COEF_REMAIN_BIN_REDUCTION << ui16AbsGoRice); + while (symbol >= (1<m_greaterOneBits[ ui16CtxNumOne ][ 1 ]; + + if (c2Idx < C2FLAG_NUMBER) + { + iRate += m_pcEstBitsSbac->m_levelAbsBits[ ui16CtxNumAbs ][ 1 ]; + } + } + } + else if( uiAbsLevel == 1 ) + { + iRate += m_pcEstBitsSbac->m_greaterOneBits[ ui16CtxNumOne ][ 0 ]; + } + else if( uiAbsLevel == 2 ) + { + iRate += m_pcEstBitsSbac->m_greaterOneBits[ ui16CtxNumOne ][ 1 ]; + iRate += m_pcEstBitsSbac->m_levelAbsBits[ ui16CtxNumAbs ][ 0 ]; + } + else + { + iRate = 0; + } + + return iRate; +} + +__inline Double TComTrQuant::xGetRateSigCoeffGroup ( UShort uiSignificanceCoeffGroup, + UShort ui16CtxNumSig ) const +{ + return xGetICost( m_pcEstBitsSbac->significantCoeffGroupBits[ ui16CtxNumSig ][ uiSignificanceCoeffGroup ] ); +} + +/** Calculates the cost of signaling the last significant coefficient in the block + * \param uiPosX X coordinate of the last significant coefficient + * \param uiPosY Y coordinate of the last significant coefficient + * \returns cost of last significant coefficient + */ +/* + * \param uiWidth width of the transform unit (TU) +*/ +__inline Double TComTrQuant::xGetRateLast ( const UInt uiPosX, + const UInt uiPosY, + const ComponentID component ) const +{ + UInt uiCtxX = g_uiGroupIdx[uiPosX]; + UInt uiCtxY = g_uiGroupIdx[uiPosY]; + + Double uiCost = m_pcEstBitsSbac->lastXBits[toChannelType(component)][ uiCtxX ] + m_pcEstBitsSbac->lastYBits[toChannelType(component)][ uiCtxY ]; + + if( uiCtxX > 3 ) + { + uiCost += xGetIEPRate() * ((uiCtxX-2)>>1); + } + if( uiCtxY > 3 ) + { + uiCost += xGetIEPRate() * ((uiCtxY-2)>>1); + } + return xGetICost( uiCost ); +} + + /** Calculates the cost for specific absolute transform level + * \param uiAbsLevel scaled quantized level + * \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC) + * \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC) + * \param ui16CtxBase current global offset for coeff_abs_level_greater1 and coeff_abs_level_greater2 + * \returns cost of given absolute transform level + */ +__inline Double TComTrQuant::xGetRateSigCoef ( UShort uiSignificance, + UShort ui16CtxNumSig ) const +{ + return xGetICost( m_pcEstBitsSbac->significantBits[ ui16CtxNumSig ][ uiSignificance ] ); +} + +/** Get the cost for a specific rate + * \param dRate rate of a bit + * \returns cost at the specific rate + */ +__inline Double TComTrQuant::xGetICost ( Double dRate ) const +{ + return m_dLambda * dRate; +} + +/** Get the cost of an equal probable bit + * \returns cost of equal probable bit + */ +__inline Double TComTrQuant::xGetIEPRate ( ) const +{ + return 32768; +} + +/** Context derivation process of coeff_abs_significant_flag + * \param uiSigCoeffGroupFlag significance map of L1 + * \param uiBlkX column of current scan position + * \param uiBlkY row of current scan position + * \param uiLog2BlkSize log2 value of block size + * \returns ctxInc for current scan position + */ +UInt TComTrQuant::getSigCoeffGroupCtxInc (const UInt* uiSigCoeffGroupFlag, + const UInt uiCGPosX, + const UInt uiCGPosY, + const UInt widthInGroups, + const UInt heightInGroups) +{ + UInt sigRight = 0; + UInt sigLower = 0; + + if (uiCGPosX < (widthInGroups - 1)) sigRight = ((uiSigCoeffGroupFlag[ (uiCGPosY * widthInGroups) + uiCGPosX + 1 ] != 0) ? 1 : 0); + if (uiCGPosY < (heightInGroups - 1)) sigLower = ((uiSigCoeffGroupFlag[ (uiCGPosY + 1) * widthInGroups + uiCGPosX ] != 0) ? 1 : 0); + + return ((sigRight + sigLower) != 0) ? 1 : 0; +} + + +/** set quantized matrix coefficient for encode + * \param scalingList quantaized matrix address + */ +Void TComTrQuant::setScalingList(TComScalingList *scalingList, const ChromaFormat format) +{ + const Int minimumQp = 0; + const Int maximumQp = SCALING_LIST_REM_NUM; + + for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++) + { + for(UInt list = 0; list < SCALING_LIST_NUM; list++) + { + for(Int qp = minimumQp; qp < maximumQp; qp++) + { + xSetScalingListEnc(scalingList,list,size,qp,format); + xSetScalingListDec(scalingList,list,size,qp,format); + setErrScaleCoeff(list,size,qp); + } + } + } +} +/** set quantized matrix coefficient for decode + * \param scalingList quantaized matrix address + */ +Void TComTrQuant::setScalingListDec(TComScalingList *scalingList, const ChromaFormat format) +{ + const Int minimumQp = 0; + const Int maximumQp = SCALING_LIST_REM_NUM; + + for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++) + { + for(UInt list = 0; list < SCALING_LIST_NUM; list++) + { + for(Int qp = minimumQp; qp < maximumQp; qp++) + { + xSetScalingListDec(scalingList,list,size,qp,format); + } + } + } +} +/** set error scale coefficients + * \param list List ID + * \param uiSize Size + * \param uiQP Quantization parameter + */ +Void TComTrQuant::setErrScaleCoeff(UInt list, UInt size, Int qp) +{ + const UInt uiLog2TrSize = g_aucConvertToBit[ g_scalingListSizeX[size] ] + 2; + const ChannelType channelType = ((list == 0) || (list == MAX_NUM_COMPONENT)) ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA; + + const Int iTransformShift = getTransformShift(channelType, uiLog2TrSize); // Represents scaling through forward transform + + UInt i,uiMaxNumCoeff = g_scalingListSize[size]; + Int *piQuantcoeff; + Double *pdErrScale; + piQuantcoeff = getQuantCoeff(list, qp,size); + pdErrScale = getErrScaleCoeff(list, size, qp); + + Double dErrScale = (Double)(1<getScalingListAddress(sizeId,listId); + quantcoeff = getQuantCoeff(listId, qp, sizeId); + + Int quantScales = g_quantScales[qp]; + + processScalingListEnc(coeff, + quantcoeff, + (quantScales << LOG2_SCALING_LIST_NEUTRAL_VALUE), + height, width, ratio, + min(MAX_MATRIX_SIZE_NUM, (Int)g_scalingListSizeX[sizeId]), + scalingList->getScalingListDC(sizeId,listId)); +} + +/** set quantized matrix coefficient for decode + * \param scalingList quantaized matrix address + * \param list List index + * \param size size index + * \param uiQP Quantization parameter + */ +Void TComTrQuant::xSetScalingListDec(TComScalingList *scalingList, UInt listId, UInt sizeId, Int qp, const ChromaFormat format) +{ + UInt width = g_scalingListSizeX[sizeId]; + UInt height = g_scalingListSizeX[sizeId]; + UInt ratio = g_scalingListSizeX[sizeId]/min(MAX_MATRIX_SIZE_NUM,(Int)g_scalingListSizeX[sizeId]); + Int *dequantcoeff; + Int *coeff = scalingList->getScalingListAddress(sizeId,listId); + + dequantcoeff = getDequantCoeff(listId, qp, sizeId); + + Int invQuantScale = g_invQuantScales[qp]; + + processScalingListDec(coeff, + dequantcoeff, + invQuantScale, + height, width, ratio, + min(MAX_MATRIX_SIZE_NUM, (Int)g_scalingListSizeX[sizeId]), + scalingList->getScalingListDC(sizeId,listId)); +} + +/** set flat matrix value to quantized coefficient + */ +Void TComTrQuant::setFlatScalingList(const ChromaFormat format) +{ + const Int minimumQp = 0; + const Int maximumQp = SCALING_LIST_REM_NUM; + + for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++) + { + for(UInt list = 0; list < SCALING_LIST_NUM; list++) + { + for(Int qp = minimumQp; qp < maximumQp; qp++) + { + xsetFlatScalingList(list,size,qp,format); + setErrScaleCoeff(list,size,qp); + } + } + } +} + +/** set flat matrix value to quantized coefficient + * \param list List ID + * \param uiQP Quantization parameter + * \param uiSize Size + */ +Void TComTrQuant::xsetFlatScalingList(UInt list, UInt size, Int qp, const ChromaFormat format) +{ + UInt i,num = g_scalingListSize[size]; + Int *quantcoeff; + Int *dequantcoeff; + + Int quantScales = g_quantScales [qp]; + Int invQuantScales = g_invQuantScales[qp] << 4; + + quantcoeff = getQuantCoeff(list, qp, size); + dequantcoeff = getDequantCoeff(list, qp, size); + + for(i=0;i 1) + { + quantcoeff[0] = quantScales / dc; + } +} + +/** set quantized matrix coefficient for decode + * \param coeff quantaized matrix address + * \param dequantcoeff quantaized matrix address + * \param invQuantScales IQ(QP%6)) + * \param height height + * \param width width + * \param ratio ratio for upscale + * \param sizuNum matrix size + * \param dc dc parameter + */ +Void TComTrQuant::processScalingListDec( Int *coeff, Int *dequantcoeff, Int invQuantScales, UInt height, UInt width, UInt ratio, Int sizuNum, UInt dc) +{ + for(UInt j=0;j 1) + { + dequantcoeff[0] = invQuantScales * dc; + } +} + +/** initialization process of scaling list array + */ +Void TComTrQuant::initScalingList() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt qp = 0; qp < SCALING_LIST_REM_NUM; qp++) + { + for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++) + { + m_quantCoef [sizeId][listId][qp] = new Int [g_scalingListSize[sizeId]]; + m_dequantCoef [sizeId][listId][qp] = new Int [g_scalingListSize[sizeId]]; + m_errScale [sizeId][listId][qp] = new Double [g_scalingListSize[sizeId]]; + } // listID loop + } + } +} + +/** destroy quantization matrix array + */ +Void TComTrQuant::destroyScalingList() +{ + for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++) + { + for(UInt qp = 0; qp < SCALING_LIST_REM_NUM; qp++) + { + if(m_quantCoef [sizeId][listId][qp]) delete [] m_quantCoef [sizeId][listId][qp]; + if(m_dequantCoef [sizeId][listId][qp]) delete [] m_dequantCoef [sizeId][listId][qp]; + if(m_errScale [sizeId][listId][qp]) delete [] m_errScale [sizeId][listId][qp]; + } + } + } +} + +Void TComTrQuant::transformSkipQuantOneSample(TComTU &rTu, const ComponentID compID, const Pel resiDiff, TCoeff* pcCoeff, const UInt uiPos, const QpParam &cQP, const Bool bUseHalfRoundingPoint) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const TComRectangle &rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + const Int iTransformShift = getTransformShift(toChannelType(compID), rTu.GetEquivalentLog2TrSize(compID)); + const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID); + const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, true); + const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem]; + + assert( scalingListType < SCALING_LIST_NUM ); + const Int *const piQuantCoeff = getQuantCoeff( scalingListType, cQP.rem, (rTu.GetEquivalentLog2TrSize(compID)-2) ); + + + /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be + * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the + * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller) + * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result + */ + + const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift; + // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset + + const Int iAdd = ( bUseHalfRoundingPoint ? 256 : (pcCU->getSlice()->getSliceType() == I_SLICE ? 171 : 85) ) << (iQBits - 9); + + TCoeff transformedCoefficient; + + // transform-skip + if (iTransformShift >= 0) + { + transformedCoefficient = resiDiff << iTransformShift; + } + else // for very high bit depths + { + const Int iTrShiftNeg = -iTransformShift; + const Int offset = 1 << (iTrShiftNeg - 1); + transformedCoefficient = ( resiDiff + offset ) >> iTrShiftNeg; + } + + // quantization + const TCoeff iSign = (transformedCoefficient < 0 ? -1: 1); + + const Int quantisationCoefficient = enableScalingLists ? piQuantCoeff[uiPos] : defaultQuantisationCoefficient; + + const Int64 tmpLevel = (Int64)abs(transformedCoefficient) * quantisationCoefficient; + + const TCoeff quantisedCoefficient = (TCoeff((tmpLevel + iAdd ) >> iQBits)) * iSign; + + const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]); + const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1; + pcCoeff[ uiPos ] = Clip3( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient ); +} + + +Void TComTrQuant::invTrSkipDeQuantOneSample( TComTU &rTu, ComponentID compID, TCoeff inSample, Pel &reconSample, const QpParam &cQP, UInt uiPos ) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const TComRectangle &rect = rTu.getRect(compID); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + const Int QP_per = cQP.per; + const Int QP_rem = cQP.rem; + const Int iTransformShift = getTransformShift(toChannelType(compID), rTu.GetEquivalentLog2TrSize(compID)); + const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID); + const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, true); + const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID); + + assert( scalingListType < SCALING_LIST_NUM ); + + const Int rightShift = (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0); + + const TCoeff transformMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]); + const TCoeff transformMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1; + + // Dequantisation + + TCoeff dequantisedSample; + + if(enableScalingLists) + { + const UInt dequantCoefBits = 1 + IQUANT_SHIFT + SCALING_LIST_BITS; + const UInt targetInputBitDepth = std::min((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - dequantCoefBits)); + + const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1)); + const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1; + + Int *piDequantCoef = getDequantCoeff(scalingListType,QP_rem,uiLog2TrSize-2); + + if(rightShift > 0) + { + const Intermediate_Int iAdd = 1 << (rightShift - 1); + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, inSample)); + const Intermediate_Int iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[uiPos]) + iAdd ) >> rightShift; + + dequantisedSample = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + else + { + const Int leftShift = -rightShift; + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, inSample)); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * piDequantCoef[uiPos]) << leftShift; + + dequantisedSample = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + else + { + const Int scale = g_invQuantScales[QP_rem]; + const Int scaleBits = (IQUANT_SHIFT + 1) ; + + const UInt targetInputBitDepth = std::min((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - scaleBits)); + const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1)); + const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1; + + if (rightShift > 0) + { + const Intermediate_Int iAdd = 1 << (rightShift - 1); + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, inSample)); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale + iAdd) >> rightShift; + + dequantisedSample = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + else + { + const Int leftShift = -rightShift; + const TCoeff clipQCoef = TCoeff(Clip3(inputMinimum, inputMaximum, inSample)); + const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale) << leftShift; + + dequantisedSample = TCoeff(Clip3(transformMinimum,transformMaximum,iCoeffQ)); + } + } + + // Inverse transform-skip + + if (iTransformShift >= 0) + { + const TCoeff offset = iTransformShift==0 ? 0 : (1 << (iTransformShift - 1)); + reconSample = Pel(( dequantisedSample + offset ) >> iTransformShift); + } + else //for very high bit depths + { + const Int iTrShiftNeg = -iTransformShift; + reconSample = Pel(dequantisedSample << iTrShiftNeg); + } +} + + +Void TComTrQuant::crossComponentPrediction( TComTU & rTu, + const ComponentID compID, + const Pel * piResiL, + const Pel * piResiC, + Pel * piResiT, + const Int width, + const Int height, + const Int strideL, + const Int strideC, + const Int strideT, + const Bool reverse ) +{ + const Pel *pResiL = piResiL; + const Pel *pResiC = piResiC; + Pel *pResiT = piResiT; + + TComDataCU *pCU = rTu.getCU(); + const Char alpha = pCU->getCrossComponentPredictionAlpha( rTu.GetAbsPartIdxTU( compID ), compID ); + const Int diffBitDepth = pCU->getSlice()->getSPS()->getDifferentialLumaChromaBitDepth(); + + for( Int y = 0; y < height; y++ ) + { + if (reverse) + { + for( Int x = 0; x < width; x++ ) + { + pResiT[x] = pResiC[x] + (( alpha * rightShift( pResiL[x], diffBitDepth) ) >> 3); + } + } + else + { + for( Int x = 0; x < width; x++ ) + { + pResiT[x] = pResiC[x] - (( alpha * rightShift(pResiL[x], diffBitDepth) ) >> 3); + } + } + + pResiL += strideL; + pResiC += strideC; + pResiT += strideT; + } +} + +//! \} diff --git a/jctvc/TLibCommon/TComTrQuant.h b/jctvc/TLibCommon/TComTrQuant.h new file mode 100644 index 0000000..1a8a087 --- /dev/null +++ b/jctvc/TLibCommon/TComTrQuant.h @@ -0,0 +1,328 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComTrQuant.h + \brief transform and quantization class (header) +*/ + +#ifndef __TCOMTRQUANT__ +#define __TCOMTRQUANT__ + +#include "CommonDef.h" +#include "TComYuv.h" +#include "TComDataCU.h" +#include "TComChromaFormat.h" +#include "ContextTables.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Constants +// ==================================================================================================================== + +#define QP_BITS 15 + +// ==================================================================================================================== +// Type definition +// ==================================================================================================================== + +typedef struct +{ + Int significantCoeffGroupBits[NUM_SIG_CG_FLAG_CTX][2 /*Flag = [0|1]*/]; + Int significantBits[NUM_SIG_FLAG_CTX][2 /*Flag = [0|1]*/]; + Int lastXBits[MAX_NUM_CHANNEL_TYPE][LAST_SIGNIFICANT_GROUPS]; + Int lastYBits[MAX_NUM_CHANNEL_TYPE][LAST_SIGNIFICANT_GROUPS]; + Int m_greaterOneBits[NUM_ONE_FLAG_CTX][2 /*Flag = [0|1]*/]; + Int m_levelAbsBits[NUM_ABS_FLAG_CTX][2 /*Flag = [0|1]*/]; + + Int blockCbpBits[NUM_QT_CBF_CTX_SETS * NUM_QT_CBF_CTX_PER_SET][2 /*Flag = [0|1]*/]; + Int blockRootCbpBits[4][2 /*Flag = [0|1]*/]; + + Int golombRiceAdaptationStatistics[RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS]; +} estBitsSbacStruct; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// QP struct +struct QpParam +{ + Int Qp; + Int per; + Int rem; + + QpParam(const Int qpy, + const ChannelType chType, + const Int qpBdOffset, + const Int chromaQPOffset, + const ChromaFormat chFmt ); + + QpParam(const TComDataCU &cu, const ComponentID compID); + +}; // END STRUCT DEFINITION QpParam + + +/// transform and quantization class +class TComTrQuant +{ +public: + TComTrQuant(); + ~TComTrQuant(); + + // initialize class + Void init ( UInt uiMaxTrSize, + Bool useRDOQ = false, + Bool useRDOQTS = false, + Bool bEnc = false, + Bool useTransformSkipFast = false +#if ADAPTIVE_QP_SELECTION + , Bool bUseAdaptQpSelect = false +#endif + ); + + // transform & inverse transform functions + Void transformNxN( TComTU & rTu, + const ComponentID compID, + Pel * pcResidual, + const UInt uiStride, + TCoeff * rpcCoeff, +#if ADAPTIVE_QP_SELECTION + TCoeff * rpcArlCoeff, +#endif + TCoeff & uiAbsSum, + const QpParam & cQP + ); + + + Void invTransformNxN( TComTU & rTu, + const ComponentID compID, + Pel *pcResidual, + const UInt uiStride, + TCoeff * pcCoeff, + const QpParam & cQP + DEBUG_STRING_FN_DECLAREP(psDebug)); + + Void invRecurTransformNxN ( const ComponentID compID, TComYuv *pResidual, TComTU &rTu ); + + Void rdpcmNxN ( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, RDPCMMode& rdpcmMode ); + Void invRdpcmNxN( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride ); + + Void applyForwardRDPCM( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, const RDPCMMode mode ); + + // Misc functions + +#if RDOQ_CHROMA_LAMBDA + Void setLambdas(const Double lambdas[MAX_NUM_COMPONENT]) { for (UInt component = 0; component < MAX_NUM_COMPONENT; component++) m_lambdas[component] = lambdas[component]; } + Void selectLambda(const ComponentID compIdx) { m_dLambda = m_lambdas[compIdx]; } +#else + Void setLambda(Double dLambda) { m_dLambda = dLambda;} +#endif + Void setRDOQOffset( UInt uiRDOQOffset ) { m_uiRDOQOffset = uiRDOQOffset; } + + estBitsSbacStruct* m_pcEstBitsSbac; + + static Int calcPatternSigCtx( const UInt* sigCoeffGroupFlag, UInt uiCGPosX, UInt uiCGPosY, UInt widthInGroups, UInt heightInGroups ); + + static Int getSigCtxInc ( Int patternSigCtx, + const TUEntropyCodingParameters &codingParameters, + const Int scanPosition, + const Int log2BlockWidth, + const Int log2BlockHeight, + const ChannelType chanType + ); + + static UInt getSigCoeffGroupCtxInc (const UInt* uiSigCoeffGroupFlag, + const UInt uiCGPosX, + const UInt uiCGPosY, + const UInt widthInGroups, + const UInt heightInGroups); + + Void initScalingList (); + Void destroyScalingList (); + Void setErrScaleCoeff ( UInt list, UInt size, Int qp ); + Double* getErrScaleCoeff ( UInt list, UInt size, Int qp ) { return m_errScale [size][list][qp]; }; //!< get Error Scale Coefficent + Double& getErrScaleCoeffNoScalingList ( UInt list, UInt size, Int qp ) { return m_errScaleNoScalingList[size][list][qp]; }; //!< get Error Scale Coefficent + Int* getQuantCoeff ( UInt list, Int qp, UInt size ) { return m_quantCoef [size][list][qp]; }; //!< get Quant Coefficent + Int* getDequantCoeff ( UInt list, Int qp, UInt size ) { return m_dequantCoef [size][list][qp]; }; //!< get DeQuant Coefficent + Void setUseScalingList ( Bool bUseScalingList){ m_scalingListEnabledFlag = bUseScalingList; }; + Bool getUseScalingList (const UInt width, const UInt height, const Bool isTransformSkip){ return m_scalingListEnabledFlag && (!isTransformSkip || ((width == 4) && (height == 4))); }; + Void setFlatScalingList (const ChromaFormat format); + Void xsetFlatScalingList ( UInt list, UInt size, Int qp, const ChromaFormat format); + Void xSetScalingListEnc ( TComScalingList *scalingList, UInt list, UInt size, Int qp, const ChromaFormat format); + Void xSetScalingListDec ( TComScalingList *scalingList, UInt list, UInt size, Int qp, const ChromaFormat format); + Void setScalingList ( TComScalingList *scalingList, const ChromaFormat format); + Void setScalingListDec ( TComScalingList *scalingList, const ChromaFormat format); + Void processScalingListEnc( Int *coeff, Int *quantcoeff, Int quantScales, UInt height, UInt width, UInt ratio, Int sizuNum, UInt dc); + Void processScalingListDec( Int *coeff, Int *dequantcoeff, Int invQuantScales, UInt height, UInt width, UInt ratio, Int sizuNum, UInt dc); +#if ADAPTIVE_QP_SELECTION + Void initSliceQpDelta() ; + Void storeSliceQpNext(TComSlice* pcSlice); + Void clearSliceARLCnt(); + Int getQpDelta(Int qp) { return m_qpDelta[qp]; } + Int* getSliceNSamples(){ return m_sliceNsamples ;} + Double* getSliceSumC() { return m_sliceSumC; } +#endif + Void transformSkipQuantOneSample(TComTU &rTu, const ComponentID compID, const Pel resiDiff, TCoeff* pcCoeff, const UInt uiPos, const QpParam &cQP, const Bool bUseHalfRoundingPoint); + Void invTrSkipDeQuantOneSample(TComTU &rTu, ComponentID compID, TCoeff pcCoeff, Pel &reconSample, const QpParam &cQP, UInt uiPos ); + +protected: +#if ADAPTIVE_QP_SELECTION + Int m_qpDelta[MAX_QP+1]; + Int m_sliceNsamples[LEVEL_RANGE+1]; + Double m_sliceSumC[LEVEL_RANGE+1] ; +#endif + TCoeff* m_plTempCoeff; + +// QpParam m_cQP; - removed - placed on the stack. +#if RDOQ_CHROMA_LAMBDA + Double m_lambdas[MAX_NUM_COMPONENT]; +#endif + Double m_dLambda; + UInt m_uiRDOQOffset; + UInt m_uiMaxTrSize; + Bool m_bEnc; + Bool m_useRDOQ; + Bool m_useRDOQTS; +#if ADAPTIVE_QP_SELECTION + Bool m_bUseAdaptQpSelect; +#endif + Bool m_useTransformSkipFast; + + Bool m_scalingListEnabledFlag; + + Int *m_quantCoef [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM][SCALING_LIST_REM_NUM]; ///< array of quantization matrix coefficient 4x4 + Int *m_dequantCoef [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM][SCALING_LIST_REM_NUM]; ///< array of dequantization matrix coefficient 4x4 + Double *m_errScale [SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM][SCALING_LIST_REM_NUM]; ///< array of quantization matrix coefficient 4x4 + Double m_errScaleNoScalingList[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM][SCALING_LIST_REM_NUM]; ///< array of quantization matrix coefficient 4x4 + +private: + // forward Transform + Void xT ( const ComponentID compID, Bool useDST, Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, Int iWidth, Int iHeight ); + + // skipping Transform + Void xTransformSkip ( Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, TComTU &rTu, const ComponentID component ); + + Void signBitHidingHDQ( const ComponentID compID, TCoeff* pQCoef, TCoeff* pCoef, TCoeff* deltaU, const TUEntropyCodingParameters &codingParameters ); + + // quantization + Void xQuant( TComTU &rTu, + TCoeff * pSrc, + TCoeff * pDes, +#if ADAPTIVE_QP_SELECTION + TCoeff *pArlDes, +#endif + TCoeff &uiAbsSum, + const ComponentID compID, + const QpParam &cQP ); + + // RDOQ functions + + Void xRateDistOptQuant ( TComTU &rTu, + TCoeff * plSrcCoeff, + TCoeff * piDstCoeff, +#if ADAPTIVE_QP_SELECTION + TCoeff *piArlDstCoeff, +#endif + TCoeff &uiAbsSum, + const ComponentID compID, + const QpParam &cQP ); + +__inline UInt xGetCodedLevel ( Double& rd64CodedCost, + Double& rd64CodedCost0, + Double& rd64CodedCostSig, + Intermediate_Int lLevelDouble, + UInt uiMaxAbsLevel, + UShort ui16CtxNumSig, + UShort ui16CtxNumOne, + UShort ui16CtxNumAbs, + UShort ui16AbsGoRice, + UInt c1Idx, + UInt c2Idx, + Int iQBits, + Double errorScale, + Bool bLast, + Bool useLimitedPrefixLength, + ChannelType channelType + ) const; + + + __inline Int xGetICRate ( UInt uiAbsLevel, + UShort ui16CtxNumOne, + UShort ui16CtxNumAbs, + UShort ui16AbsGoRice, + UInt c1Idx, + UInt c2Idx, + Bool useLimitedPrefixLength, + ChannelType channelType + ) const; + + __inline Double xGetRateLast ( const UInt uiPosX, const UInt uiPosY, const ComponentID component ) const; + __inline Double xGetRateSigCoeffGroup( UShort uiSignificanceCoeffGroup, UShort ui16CtxNumSig ) const; + __inline Double xGetRateSigCoef ( UShort uiSignificance, UShort ui16CtxNumSig ) const; + __inline Double xGetICost ( Double dRate ) const; + __inline Double xGetIEPRate ( ) const; + + + // dequantization + Void xDeQuant( TComTU &rTu, + const TCoeff * pSrc, + TCoeff * pDes, + const ComponentID compID, + const QpParam &cQP ); + + // inverse transform + Void xIT ( const ComponentID compID, Bool useDST, TCoeff* plCoef, Pel* pResidual, UInt uiStride, Int iWidth, Int iHeight ); + + // inverse skipping transform + Void xITransformSkip ( TCoeff* plCoef, Pel* pResidual, UInt uiStride, TComTU &rTu, const ComponentID component ); + +public: + static Void crossComponentPrediction( TComTU &rTu, + const ComponentID compID, + const Pel *piResiL, + const Pel *piResiC, + Pel *piResiT, + const Int width, + const Int height, + const Int strideL, + const Int strideC, + const Int strideT, + const Bool reverse); + +};// END CLASS DEFINITION TComTrQuant + +//! \} + +#endif // __TCOMTRQUANT__ diff --git a/jctvc/TLibCommon/TComWeightPrediction.cpp b/jctvc/TLibCommon/TComWeightPrediction.cpp new file mode 100644 index 0000000..0cf3243 --- /dev/null +++ b/jctvc/TLibCommon/TComWeightPrediction.cpp @@ -0,0 +1,376 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComWeightPrediction.h + \brief weighting prediction class (header) +*/ + +// Include files +#include "TComSlice.h" +#include "TComWeightPrediction.h" +#include "TComInterpolationFilter.h" + + +static inline Pel weightBidir( Int w0, Pel P0, Int w1, Pel P1, Int round, Int shift, Int offset, Int clipBD) +{ + return ClipBD( ( (w0*(P0 + IF_INTERNAL_OFFS) + w1*(P1 + IF_INTERNAL_OFFS) + round + (offset << (shift-1))) >> shift ), clipBD ); +} + + +static inline Pel weightUnidir( Int w0, Pel P0, Int round, Int shift, Int offset, Int clipBD) +{ + return ClipBD( ( (w0*(P0 + IF_INTERNAL_OFFS) + round) >> shift ) + offset, clipBD ); +} + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +TComWeightPrediction::TComWeightPrediction() +{ +} + + +/** weighted averaging for bi-pred + * \param TComYuv* pcYuvSrc0 + * \param TComYuv* pcYuvSrc1 + * \param iPartUnitIdx + * \param iWidth + * \param iHeight + * \param WPScalingParam *wp0 + * \param WPScalingParam *wp1 + * \param TComYuv* rpcYuvDst + * \returns Void + */ +Void TComWeightPrediction::addWeightBi( const TComYuv *pcYuvSrc0, + const TComYuv *pcYuvSrc1, + const UInt iPartUnitIdx, + const UInt uiWidth, + const UInt uiHeight, + const WPScalingParam *const wp0, + const WPScalingParam *const wp1, + TComYuv *const rpcYuvDst, + const Bool bRoundLuma ) +{ + + const Bool enableRounding[MAX_NUM_COMPONENT]={ bRoundLuma, true, true }; + + const UInt numValidComponent = pcYuvSrc0->getNumberValidComponents(); + + for(Int componentIndex=0; componentIndexgetAddr( compID, iPartUnitIdx ); + const Pel* pSrc1 = pcYuvSrc1->getAddr( compID, iPartUnitIdx ); + Pel* pDst = rpcYuvDst->getAddr( compID, iPartUnitIdx ); + + // Luma : -------------------------------------------- + const Int w0 = wp0[compID].w; + const Int offset = wp0[compID].offset; + const Int clipBD = g_bitDepth[toChannelType(compID)]; + const Int shiftNum = std::max(2, (IF_INTERNAL_PREC - clipBD)); + const Int shift = wp0[compID].shift + shiftNum; + const Int round = (enableRounding[compID] && (shift > 0)) ? (1<<(shift-1)) : 0; + const Int w1 = wp1[compID].w; + const UInt csx = pcYuvSrc0->getComponentScaleX(compID); + const UInt csy = pcYuvSrc0->getComponentScaleY(compID); + const Int iHeight = uiHeight>>csy; + const Int iWidth = uiWidth>>csx; + + const UInt iSrc0Stride = pcYuvSrc0->getStride(compID); + const UInt iSrc1Stride = pcYuvSrc1->getStride(compID); + const UInt iDstStride = rpcYuvDst->getStride(compID); + + for ( Int y = iHeight-1; y >= 0; y-- ) + { + // do it in batches of 4 (partial unroll) + Int x = iWidth-1; + for ( ; x >= 3; ) + { + pDst[x] = weightBidir(w0,pSrc0[x], w1,pSrc1[x], round, shift, offset, clipBD); x--; + pDst[x] = weightBidir(w0,pSrc0[x], w1,pSrc1[x], round, shift, offset, clipBD); x--; + pDst[x] = weightBidir(w0,pSrc0[x], w1,pSrc1[x], round, shift, offset, clipBD); x--; + pDst[x] = weightBidir(w0,pSrc0[x], w1,pSrc1[x], round, shift, offset, clipBD); x--; + } + for( ; x >= 0; x-- ) + { + pDst[x] = weightBidir(w0,pSrc0[x], w1,pSrc1[x], round, shift, offset, clipBD); + } + + pSrc0 += iSrc0Stride; + pSrc1 += iSrc1Stride; + pDst += iDstStride; + } // y loop + } // compID loop +} + + +/** weighted averaging for uni-pred + * \param TComYuv* pcYuvSrc0 + * \param iPartUnitIdx + * \param iWidth + * \param iHeight + * \param WPScalingParam *wp0 + * \param TComYuv* rpcYuvDst + * \returns Void + */ +Void TComWeightPrediction::addWeightUni( const TComYuv *const pcYuvSrc0, + const UInt iPartUnitIdx, + const UInt uiWidth, + const UInt uiHeight, + const WPScalingParam *const wp0, + TComYuv *const pcYuvDst ) +{ + const UInt numValidComponent = pcYuvSrc0->getNumberValidComponents(); + + for(Int componentIndex=0; componentIndexgetAddr( compID, iPartUnitIdx ); + Pel* pDst = pcYuvDst->getAddr( compID, iPartUnitIdx ); + + // Luma : -------------------------------------------- + const Int w0 = wp0[compID].w; + const Int offset = wp0[compID].offset; + const Int clipBD = g_bitDepth[toChannelType(compID)]; + const Int shiftNum = std::max(2, (IF_INTERNAL_PREC - clipBD)); + const Int shift = wp0[compID].shift + shiftNum; + const Int round = (shift > 0) ? (1<<(shift-1)) : 0; + const UInt iSrc0Stride = pcYuvSrc0->getStride(compID); + const UInt iDstStride = pcYuvDst->getStride(compID); + const UInt csx = pcYuvSrc0->getComponentScaleX(compID); + const UInt csy = pcYuvSrc0->getComponentScaleY(compID); + const Int iHeight = uiHeight>>csy; + const Int iWidth = uiWidth>>csx; + + for (Int y = iHeight-1; y >= 0; y-- ) + { + Int x = iWidth-1; + for ( ; x >= 3; ) + { + pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clipBD); x--; + pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clipBD); x--; + pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clipBD); x--; + pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clipBD); x--; + } + for( ; x >= 0; x--) + { + pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clipBD); + } + pSrc0 += iSrc0Stride; + pDst += iDstStride; + } + } +} + + +//======================================================= +// getWpScaling() +//======================================================= +/** derivation of wp tables + * \param TComDataCU* pcCU + * \param iRefIdx0 + * \param iRefIdx1 + * \param WPScalingParam *&wp0 + * \param WPScalingParam *&wp1 + * \param ibdi + * \returns Void + */ +Void TComWeightPrediction::getWpScaling( TComDataCU *const pcCU, + const Int iRefIdx0, + const Int iRefIdx1, + WPScalingParam *&wp0, + WPScalingParam *&wp1) +{ + assert(iRefIdx0 >= 0 || iRefIdx1 >= 0); + + TComSlice *const pcSlice = pcCU->getSlice(); + const Bool wpBiPred = pcCU->getSlice()->getPPS()->getWPBiPred(); + const Bool bBiDir = (iRefIdx0>=0 && iRefIdx1>=0); + const Bool bUniDir = !bBiDir; + + if ( bUniDir || wpBiPred ) + { // explicit -------------------- + if ( iRefIdx0 >= 0 ) + { + pcSlice->getWpScaling(REF_PIC_LIST_0, iRefIdx0, wp0); + } + if ( iRefIdx1 >= 0 ) + { + pcSlice->getWpScaling(REF_PIC_LIST_1, iRefIdx1, wp1); + } + } + else + { + assert(0); + } + + if ( iRefIdx0 < 0 ) + { + wp0 = NULL; + } + if ( iRefIdx1 < 0 ) + { + wp1 = NULL; + } + + const UInt numValidComponent = pcCU->getPic()->getNumberValidComponents(); + const Bool bUseHighPrecisionPredictionWeighting = pcSlice->getSPS()->getUseHighPrecisionPredictionWeighting(); + + if ( bBiDir ) + { // Bi-Dir case + for ( Int yuv=0 ; yuv=0) ? wp0 : wp1 ; + + for ( Int yuv=0 ; yuv=1) ? (1 << (pwp[yuv].uiLog2WeightDenom-1)) : (0); + } + } +} + + +/** weighted prediction for bi-pred + * \param TComDataCU* pcCU + * \param TComYuv* pcYuvSrc0 + * \param TComYuv* pcYuvSrc1 + * \param iRefIdx0 + * \param iRefIdx1 + * \param uiPartIdx + * \param iWidth + * \param iHeight + * \param TComYuv* rpcYuvDst + * \returns Void + */ +Void TComWeightPrediction::xWeightedPredictionBi( TComDataCU *const pcCU, + const TComYuv *const pcYuvSrc0, + const TComYuv *const pcYuvSrc1, + const Int iRefIdx0, + const Int iRefIdx1, + const UInt uiPartIdx, + const Int iWidth, + const Int iHeight, + TComYuv *rpcYuvDst ) +{ + WPScalingParam *pwp0; + WPScalingParam *pwp1; + + assert(pcCU->getSlice()->getPPS()->getWPBiPred()); + + getWpScaling(pcCU, iRefIdx0, iRefIdx1, pwp0, pwp1); + + if( iRefIdx0 >= 0 && iRefIdx1 >= 0 ) + { + addWeightBi(pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp0, pwp1, rpcYuvDst ); + } + else if ( iRefIdx0 >= 0 && iRefIdx1 < 0 ) + { + addWeightUni( pcYuvSrc0, uiPartIdx, iWidth, iHeight, pwp0, rpcYuvDst ); + } + else if ( iRefIdx0 < 0 && iRefIdx1 >= 0 ) + { + addWeightUni( pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp1, rpcYuvDst ); + } + else + { + assert (0); + } +} + + +/** weighted prediction for uni-pred + * \param TComDataCU* pcCU + * \param TComYuv* pcYuvSrc + * \param uiPartAddr + * \param iWidth + * \param iHeight + * \param eRefPicList + * \param TComYuv* pcYuvPred + * \param iPartIdx + * \param iRefIdx + * \returns Void + */ +Void TComWeightPrediction::xWeightedPredictionUni( TComDataCU *const pcCU, + const TComYuv *const pcYuvSrc, + const UInt uiPartAddr, + const Int iWidth, + const Int iHeight, + const RefPicList eRefPicList, + TComYuv *pcYuvPred, + const Int iRefIdx_input) +{ + WPScalingParam *pwp, *pwpTmp; + + Int iRefIdx=iRefIdx_input; + if ( iRefIdx < 0 ) + { + iRefIdx = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr ); + } + assert (iRefIdx >= 0); + + if ( eRefPicList == REF_PIC_LIST_0 ) + { + getWpScaling(pcCU, iRefIdx, -1, pwp, pwpTmp); + } + else + { + getWpScaling(pcCU, -1, iRefIdx, pwpTmp, pwp); + } + addWeightUni( pcYuvSrc, uiPartAddr, iWidth, iHeight, pwp, pcYuvPred ); +} diff --git a/jctvc/TLibCommon/TComWeightPrediction.h b/jctvc/TLibCommon/TComWeightPrediction.h new file mode 100644 index 0000000..9653fa4 --- /dev/null +++ b/jctvc/TLibCommon/TComWeightPrediction.h @@ -0,0 +1,101 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComWeightPrediction.h + \brief weighting prediction class (header) +*/ + +#ifndef __TCOMWEIGHTPREDICTION__ +#define __TCOMWEIGHTPREDICTION__ + + +// Include files +#include "TComPic.h" +#include "TComMotionInfo.h" +#include "TComPattern.h" +#include "TComTrQuant.h" +#include "TComInterpolationFilter.h" + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== +/// weighting prediction class +class TComWeightPrediction +{ +public: + TComWeightPrediction(); + + Void getWpScaling( TComDataCU *const pcCU, + const Int iRefIdx0, + const Int iRefIdx1, + WPScalingParam *&wp0, + WPScalingParam *&wp1); + + Void addWeightBi( const TComYuv *pcYuvSrc0, + const TComYuv *pcYuvSrc1, + const UInt iPartUnitIdx, + const UInt uiWidth, + const UInt uiHeight, + const WPScalingParam *const wp0, + const WPScalingParam *const wp1, + TComYuv *const rpcYuvDst, + const Bool bRoundLuma=true ); + + Void addWeightUni( const TComYuv *const pcYuvSrc0, + const UInt iPartUnitIdx, + const UInt uiWidth, + const UInt uiHeight, + const WPScalingParam *const wp0, + TComYuv *const rpcYuvDst ); + + Void xWeightedPredictionUni( TComDataCU *const pcCU, + const TComYuv *const pcYuvSrc, + const UInt uiPartAddr, + const Int iWidth, + const Int iHeight, + const RefPicList eRefPicList, + TComYuv *pcYuvPred, + const Int iRefIdx=-1 ); + + Void xWeightedPredictionBi( TComDataCU *const pcCU, + const TComYuv *const pcYuvSrc0, + const TComYuv *const pcYuvSrc1, + const Int iRefIdx0, + const Int iRefIdx1, + const UInt uiPartIdx, + const Int iWidth, + const Int iHeight, + TComYuv *pcYuvDst ); +}; + +#endif diff --git a/jctvc/TLibCommon/TComYuv.cpp b/jctvc/TLibCommon/TComYuv.cpp new file mode 100644 index 0000000..df3eed4 --- /dev/null +++ b/jctvc/TLibCommon/TComYuv.cpp @@ -0,0 +1,426 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComYuv.cpp + \brief general YUV buffer class + \todo this should be merged with TComPicYuv +*/ + +#include +#include +#include +#include + +#include "CommonDef.h" +#include "TComYuv.h" +#include "TComInterpolationFilter.h" + +//! \ingroup TLibCommon +//! \{ + +TComYuv::TComYuv() +{ + for(Int comp=0; comp>uiPartDepth; + const Int iHeight = getHeight(ch)>>uiPartDepth; + + const Pel* pSrc = getAddr(ch, uiPartIdx, iWidth); + Pel* pDst = pcPicYuvDst->getAddr ( ch, ctuRsAddr, uiAbsZorderIdx ); + + const UInt iSrcStride = getStride(ch); + const UInt iDstStride = pcPicYuvDst->getStride(ch); + + for ( Int y = iHeight; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, sizeof(Pel)*iWidth); + pDst += iDstStride; + pSrc += iSrcStride; + } +} + + + + +Void TComYuv::copyFromPicYuv ( const TComPicYuv* pcPicYuvSrc, const UInt ctuRsAddr, const UInt uiAbsZorderIdx ) +{ + for(Int ch=0; chgetAddr ( ch, ctuRsAddr, uiAbsZorderIdx ); + + const UInt iDstStride = getStride(ch); + const UInt iSrcStride = pcPicYuvSrc->getStride(ch); + const Int iWidth=getWidth(ch); + const Int iHeight=getHeight(ch); + + for (Int y = iHeight; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, sizeof(Pel)*iWidth); + pDst += iDstStride; + pSrc += iSrcStride; + } +} + + + + +Void TComYuv::copyToPartYuv( TComYuv* pcYuvDst, const UInt uiDstPartIdx ) const +{ + for(Int ch=0; chgetAddr( ch, uiDstPartIdx ); + + const UInt iSrcStride = getStride(ch); + const UInt iDstStride = pcYuvDst->getStride(ch); + const Int iWidth=getWidth(ch); + const Int iHeight=getHeight(ch); + + for (Int y = iHeight; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, sizeof(Pel)*iWidth); + pDst += iDstStride; + pSrc += iSrcStride; + } +} + + + + +Void TComYuv::copyPartToYuv( TComYuv* pcYuvDst, const UInt uiSrcPartIdx ) const +{ + for(Int ch=0; chgetAddr(ch, 0 ); + + const UInt iSrcStride = getStride(ch); + const UInt iDstStride = pcYuvDst->getStride(ch); + + const UInt uiHeight = pcYuvDst->getHeight(ch); + const UInt uiWidth = pcYuvDst->getWidth(ch); + + for ( UInt y = uiHeight; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, sizeof(Pel)*uiWidth); + pDst += iDstStride; + pSrc += iSrcStride; + } +} + + + + +Void TComYuv::copyPartToPartYuv ( TComYuv* pcYuvDst, const UInt uiPartIdx, const UInt iWidth, const UInt iHeight ) const +{ + for(Int ch=0; ch>getComponentScaleX(ComponentID(ch)), iHeight>>getComponentScaleY(ComponentID(ch)) ); +} + +Void TComYuv::copyPartToPartComponent ( const ComponentID ch, TComYuv* pcYuvDst, const UInt uiPartIdx, const UInt iWidthComponent, const UInt iHeightComponent ) const +{ + const Pel* pSrc = getAddr(ch, uiPartIdx); + Pel* pDst = pcYuvDst->getAddr(ch, uiPartIdx); + if( pSrc == pDst ) + { + //th not a good idea + //th best would be to fix the caller + return ; + } + + const UInt iSrcStride = getStride(ch); + const UInt iDstStride = pcYuvDst->getStride(ch); + for ( UInt y = iHeightComponent; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, iWidthComponent * sizeof(Pel) ); + pSrc += iSrcStride; + pDst += iDstStride; + } +} + + + + +Void TComYuv::copyPartToPartComponentMxN ( const ComponentID ch, TComYuv* pcYuvDst, const TComRectangle &rect) const +{ + const Pel* pSrc = getAddrPix( ch, rect.x0, rect.y0 ); + Pel* pDst = pcYuvDst->getAddrPix( ch, rect.x0, rect.y0 ); + if( pSrc == pDst ) + { + //th not a good idea + //th best would be to fix the caller + return ; + } + + const UInt iSrcStride = getStride(ch); + const UInt iDstStride = pcYuvDst->getStride(ch); + const UInt uiHeightComponent=rect.height; + const UInt uiWidthComponent=rect.width; + for ( UInt y = uiHeightComponent; y != 0; y-- ) + { + ::memcpy( pDst, pSrc, uiWidthComponent * sizeof( Pel ) ); + pSrc += iSrcStride; + pDst += iDstStride; + } +} + + + + +Void TComYuv::addClip( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt uiTrUnitIdx, const UInt uiPartSize ) +{ + for(Int chan=0; chan>getComponentScaleX(ch); + const Int uiPartHeight=uiPartSize>>getComponentScaleY(ch); + + const Pel* pSrc0 = pcYuvSrc0->getAddr(ch, uiTrUnitIdx, uiPartWidth ); + const Pel* pSrc1 = pcYuvSrc1->getAddr(ch, uiTrUnitIdx, uiPartWidth ); + Pel* pDst = getAddr(ch, uiTrUnitIdx, uiPartWidth ); + + const UInt iSrc0Stride = pcYuvSrc0->getStride(ch); + const UInt iSrc1Stride = pcYuvSrc1->getStride(ch); + const UInt iDstStride = getStride(ch); + const Int clipbd = g_bitDepth[toChannelType(ch)]; +#if O0043_BEST_EFFORT_DECODING + const Int bitDepthDelta = g_bitDepthInStream[toChannelType(ch)] - g_bitDepth[toChannelType(ch)]; +#endif + + for ( Int y = uiPartHeight-1; y >= 0; y-- ) + { + for ( Int x = uiPartWidth-1; x >= 0; x-- ) + { +#if O0043_BEST_EFFORT_DECODING + pDst[x] = Pel(ClipBD( Int(pSrc0[x]) + rightShiftEvenRounding(pSrc1[x], bitDepthDelta), clipbd)); +#else + pDst[x] = Pel(ClipBD( Int(pSrc0[x]) + Int(pSrc1[x]), clipbd)); +#endif + } + pSrc0 += iSrc0Stride; + pSrc1 += iSrc1Stride; + pDst += iDstStride; + } + } +} + + + + +Void TComYuv::subtract( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt uiTrUnitIdx, const UInt uiPartSize ) +{ + for(Int chan=0; chan>getComponentScaleX(ch); + const Int uiPartHeight=uiPartSize>>getComponentScaleY(ch); + + const Pel* pSrc0 = pcYuvSrc0->getAddr( ch, uiTrUnitIdx, uiPartWidth ); + const Pel* pSrc1 = pcYuvSrc1->getAddr( ch, uiTrUnitIdx, uiPartWidth ); + Pel* pDst = getAddr( ch, uiTrUnitIdx, uiPartWidth ); + + const Int iSrc0Stride = pcYuvSrc0->getStride(ch); + const Int iSrc1Stride = pcYuvSrc1->getStride(ch); + const Int iDstStride = getStride(ch); + + for (Int y = uiPartHeight-1; y >= 0; y-- ) + { + for (Int x = uiPartWidth-1; x >= 0; x-- ) + { + pDst[x] = pSrc0[x] - pSrc1[x]; + } + pSrc0 += iSrc0Stride; + pSrc1 += iSrc1Stride; + pDst += iDstStride; + } + } +} + + + + +Void TComYuv::addAvg( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt iPartUnitIdx, const UInt uiWidth, const UInt uiHeight ) +{ + for(Int chan=0; changetAddr( ch, iPartUnitIdx ); + const Pel* pSrc1 = pcYuvSrc1->getAddr( ch, iPartUnitIdx ); + Pel* pDst = getAddr( ch, iPartUnitIdx ); + + const UInt iSrc0Stride = pcYuvSrc0->getStride(ch); + const UInt iSrc1Stride = pcYuvSrc1->getStride(ch); + const UInt iDstStride = getStride(ch); + const Int clipbd = g_bitDepth[toChannelType(ch)]; + const Int shiftNum = std::max(2, (IF_INTERNAL_PREC - clipbd)) + 1; + const Int offset = ( 1 << ( shiftNum - 1 ) ) + 2 * IF_INTERNAL_OFFS; + + const Int iWidth = uiWidth >> getComponentScaleX(ch); + const Int iHeight = uiHeight >> getComponentScaleY(ch); + + if (iWidth&1) + { + assert(0); + exit(-1); + } + else if (iWidth&2) + { + for ( Int y = 0; y < iHeight; y++ ) + { + for (Int x=0 ; x < iWidth; x+=2 ) + { + pDst[ x + 0 ] = ClipBD( rightShift(( pSrc0[ x + 0 ] + pSrc1[ x + 0 ] + offset ), shiftNum), clipbd ); + pDst[ x + 1 ] = ClipBD( rightShift(( pSrc0[ x + 1 ] + pSrc1[ x + 1 ] + offset ), shiftNum), clipbd ); + } + pSrc0 += iSrc0Stride; + pSrc1 += iSrc1Stride; + pDst += iDstStride; + } + } + else + { + for ( Int y = 0; y < iHeight; y++ ) + { + for (Int x=0 ; x < iWidth; x+=4 ) + { + pDst[ x + 0 ] = ClipBD( rightShift(( pSrc0[ x + 0 ] + pSrc1[ x + 0 ] + offset ), shiftNum), clipbd ); + pDst[ x + 1 ] = ClipBD( rightShift(( pSrc0[ x + 1 ] + pSrc1[ x + 1 ] + offset ), shiftNum), clipbd ); + pDst[ x + 2 ] = ClipBD( rightShift(( pSrc0[ x + 2 ] + pSrc1[ x + 2 ] + offset ), shiftNum), clipbd ); + pDst[ x + 3 ] = ClipBD( rightShift(( pSrc0[ x + 3 ] + pSrc1[ x + 3 ] + offset ), shiftNum), clipbd ); + } + pSrc0 += iSrc0Stride; + pSrc1 += iSrc1Stride; + pDst += iDstStride; + } + } + } +} + +Void TComYuv::removeHighFreq( const TComYuv* pcYuvSrc, const UInt uiPartIdx, const UInt uiWidth, UInt const uiHeight ) +{ + for(Int chan=0; changetAddr(ch, uiPartIdx); + Pel* pDst = getAddr(ch, uiPartIdx); + + const Int iSrcStride = pcYuvSrc->getStride(ch); + const Int iDstStride = getStride(ch); + const Int iWidth = uiWidth >>getComponentScaleX(ch); + const Int iHeight = uiHeight>>getComponentScaleY(ch); + + for ( Int y = iHeight-1; y >= 0; y-- ) + { + for ( Int x = iWidth-1; x >= 0; x-- ) + { +#if DISABLING_CLIP_FOR_BIPREDME + pDst[x ] = (2 * pDst[x]) - pSrc[x]; +#else + pDst[x ] = Clip((2 * pDst[x]) - pSrc[x], chType); +#endif + } + pSrc += iSrcStride; + pDst += iDstStride; + } + } +} + +//! \} diff --git a/jctvc/TLibCommon/TComYuv.h b/jctvc/TLibCommon/TComYuv.h new file mode 100644 index 0000000..a005162 --- /dev/null +++ b/jctvc/TLibCommon/TComYuv.h @@ -0,0 +1,207 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TComYuv.h + \brief general YUV buffer class (header) + \todo this should be merged with TComPicYuv \n + check usage of removeHighFreq function +*/ + +#ifndef __TCOMYUV__ +#define __TCOMYUV__ +#include +#include "CommonDef.h" +#include "TComPicYuv.h" +#include "TComRectangle.h" + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// general YUV buffer class +class TComYuv +{ +private: + + // ------------------------------------------------------------------------------------------------------------------ + // YUV buffer + // ------------------------------------------------------------------------------------------------------------------ + + Pel* m_apiBuf[MAX_NUM_COMPONENT]; + + // ------------------------------------------------------------------------------------------------------------------ + // Parameter for general YUV buffer usage + // ------------------------------------------------------------------------------------------------------------------ + + UInt m_iWidth; + UInt m_iHeight; + ChromaFormat m_chromaFormatIDC; ////< Chroma Format + + // dims 16x16 + // blkSize=4x4 + + // these functions assume a square CU, of size width*width, split into square TUs each of size blkSize*blkSize. + // iTransUnitIdx is the raster-scanned index of the sub-block (TU) in question. + // eg for a 16x16 CU, with 4x4 TUs: + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + + // So, for iTransUnitIdx=14, 14*4 & 15 =8=X offset. + // 14*4 / 16 =3=Y block offset + // 3*4*16 = Y offset within buffer + + +public: + + TComYuv (); + virtual ~TComYuv (); + + // ------------------------------------------------------------------------------------------------------------------ + // Memory management + // ------------------------------------------------------------------------------------------------------------------ + + Void create ( const UInt iWidth, const UInt iHeight, const ChromaFormat chromaFormatIDC ); ///< Create YUV buffer + Void destroy (); ///< Destroy YUV buffer + Void clear (); ///< clear YUV buffer + + // ------------------------------------------------------------------------------------------------------------------ + // Copy, load, store YUV buffer + // ------------------------------------------------------------------------------------------------------------------ + + // Copy YUV buffer to picture buffer + Void copyToPicYuv ( TComPicYuv* pcPicYuvDst, const UInt ctuRsAddr, const UInt uiAbsZorderIdx, const UInt uiPartDepth = 0, const UInt uiPartIdx = 0 ) const ; + Void copyToPicComponent ( const ComponentID id, TComPicYuv* pcPicYuvDst, const UInt iCtuRsAddr, const UInt uiAbsZorderIdx, const UInt uiPartDepth = 0, const UInt uiPartIdx = 0 ) const ; + + // Copy YUV buffer from picture buffer + Void copyFromPicYuv ( const TComPicYuv* pcPicYuvSrc, const UInt ctuRsAddr, const UInt uiAbsZorderIdx ); + Void copyFromPicComponent ( const ComponentID id, const TComPicYuv* pcPicYuvSrc, const UInt iCtuRsAddr, const UInt uiAbsZorderIdx ); + + // Copy Small YUV buffer to the part of other Big YUV buffer + Void copyToPartYuv ( TComYuv* pcYuvDst, const UInt uiDstPartIdx ) const ; + Void copyToPartComponent ( const ComponentID id, TComYuv* pcYuvDst, const UInt uiDstPartIdx ) const ; + + // Copy the part of Big YUV buffer to other Small YUV buffer + Void copyPartToYuv ( TComYuv* pcYuvDst, const UInt uiSrcPartIdx ) const; + Void copyPartToComponent ( const ComponentID id, TComYuv* pcYuvDst, const UInt uiSrcPartIdx ) const; + + // Copy YUV partition buffer to other YUV partition buffer + Void copyPartToPartYuv ( TComYuv* pcYuvDst, const UInt uiPartIdx, const UInt uiWidth, const UInt uiHeight ) const; + Void copyPartToPartComponent ( const ComponentID id, TComYuv* pcYuvDst, const UInt uiPartIdx, const UInt uiWidthComponent, const UInt uiHeightComponent ) const; + + // Copy YUV partition buffer to other YUV partition buffer for non-square blocks + Void copyPartToPartComponentMxN ( const ComponentID id, TComYuv* pcYuvDst, const TComRectangle &rect ) const; + + // ------------------------------------------------------------------------------------------------------------------ + // Algebraic operation for YUV buffer + // ------------------------------------------------------------------------------------------------------------------ + + // Clip(pcYuvSrc0 + pcYuvSrc1) -> m_apiBuf + Void addClip ( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt uiTrUnitIdx, const UInt uiPartSize ); + + // pcYuvSrc0 - pcYuvSrc1 -> m_apiBuf + Void subtract ( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt uiTrUnitIdx, const UInt uiPartSize ); + + // (pcYuvSrc0 + pcYuvSrc1)/2 for YUV partition + Void addAvg ( const TComYuv* pcYuvSrc0, const TComYuv* pcYuvSrc1, const UInt iPartUnitIdx, const UInt iWidth, const UInt iHeight ); + + Void removeHighFreq ( const TComYuv* pcYuvSrc, const UInt uiPartIdx, const UInt uiWidth, const UInt uiHeight ); + + // ------------------------------------------------------------------------------------------------------------------ + // Access function for YUV buffer + // ------------------------------------------------------------------------------------------------------------------ + + // Access starting position of YUV buffer + Pel* getAddr (const ComponentID id) { return m_apiBuf[id]; } + const Pel* getAddr (const ComponentID id) const { return m_apiBuf[id]; } + + // Access starting position of YUV partition unit buffer + Pel* getAddr (const ComponentID id, const UInt uiPartUnitIdx) + { + Int blkX = g_auiRasterToPelX[ g_auiZscanToRaster[ uiPartUnitIdx ] ] >> getComponentScaleX(id); + Int blkY = g_auiRasterToPelY[ g_auiZscanToRaster[ uiPartUnitIdx ] ] >> getComponentScaleY(id); + assert((blkX> getComponentScaleX(id); + Int blkY = g_auiRasterToPelY[ g_auiZscanToRaster[ uiPartUnitIdx ] ] >> getComponentScaleY(id); + assert((blkX> getComponentScaleX(id); } + UInt getHeight (const ComponentID id) const { return m_iHeight >> getComponentScaleY(id); } + UInt getWidth (const ComponentID id) const { return m_iWidth >> getComponentScaleX(id); } + ChromaFormat getChromaFormat () const { return m_chromaFormatIDC; } + UInt getNumberValidComponents () const { return ::getNumberValidComponents(m_chromaFormatIDC); } + UInt getComponentScaleX (const ComponentID id) const { return ::getComponentScaleX(id, m_chromaFormatIDC); } + UInt getComponentScaleY (const ComponentID id) const { return ::getComponentScaleY(id, m_chromaFormatIDC); } + +};// END CLASS DEFINITION TComYuv + +//! \} + +#endif // __TCOMYUV__ diff --git a/jctvc/TLibCommon/TypeDef.h b/jctvc/TLibCommon/TypeDef.h new file mode 100644 index 0000000..7d334c7 --- /dev/null +++ b/jctvc/TLibCommon/TypeDef.h @@ -0,0 +1,826 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TypeDef.h + \brief Define basic types, new types and enumerations +*/ + +#ifndef __TYPEDEF__ +#define __TYPEDEF__ + +#include + +//! \ingroup TLibCommon +//! \{ + +// ==================================================================================================================== +// Debugging +// ==================================================================================================================== + +// #define DEBUG_STRING // enable to print out final decision debug info at encoder and decoder +// #define DEBUG_ENCODER_SEARCH_BINS // enable to print out each bin as it is coded during encoder search +// #define DEBUG_CABAC_BINS // enable to print out each bin as it is coded during final encode and decode +// #define DEBUG_INTRA_SEARCH_COSTS // enable to print out the cost for each mode during encoder search +// #define DEBUG_TRANSFORM_AND_QUANTISE // enable to print out each TU as it passes through the transform-quantise-dequantise-inverseTransform process + +#ifdef DEBUG_STRING + #define DEBUG_STRING_PASS_INTO(name) , name + #define DEBUG_STRING_PASS_INTO_OPTIONAL(name, exp) , (exp==0)?0:name + #define DEBUG_STRING_FN_DECLARE(name) , std::string &name + #define DEBUG_STRING_FN_DECLAREP(name) , std::string *name + #define DEBUG_STRING_NEW(name) std::string name; + #define DEBUG_STRING_OUTPUT(os, name) os << name; + #define DEBUG_STRING_APPEND(str1, str2) str1+=str2; + #define DEBUG_STRING_SWAP(str1, str2) str1.swap(str2); + #define DEBUG_STRING_CHANNEL_CONDITION(compID) (true) + #include + #include +#else + #define DEBUG_STRING_PASS_INTO(name) + #define DEBUG_STRING_PASS_INTO_OPTIONAL(name, exp) + #define DEBUG_STRING_FN_DECLARE(name) + #define DEBUG_STRING_FN_DECLAREP(name) + #define DEBUG_STRING_NEW(name) + #define DEBUG_STRING_OUTPUT(os, name) + #define DEBUG_STRING_APPEND(str1, str2) + #define DEBUG_STRING_SWAP(srt1, str2) + #define DEBUG_STRING_CHANNEL_CONDITION(compID) +#endif + + +// ==================================================================================================================== +// Tool Switches +// ==================================================================================================================== + +#define HARMONIZE_GOP_FIRST_FIELD_COUPLE 1 +#define EFFICIENT_FIELD_IRAP 1 +#define ALLOW_RECOVERY_POINT_AS_RAP 1 +#define BUGFIX_INTRAPERIOD 1 + +#define SAO_ENCODE_ALLOW_USE_PREDEBLOCK 1 + +#define TILE_SIZE_CHECK 1 + +#define MAX_NUM_PICS_IN_SOP 1024 + +#define MAX_NESTING_NUM_OPS 1024 +#define MAX_NESTING_NUM_LAYER 64 + +#define MAX_VPS_NUM_HRD_PARAMETERS 1 +#define MAX_VPS_OP_SETS_PLUS1 1024 +#define MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 1 + +#define MAXIMUM_INTRA_FILTERED_WIDTH 16 +#define MAXIMUM_INTRA_FILTERED_HEIGHT 16 + +#define MAX_CPB_CNT 32 ///< Upper bound of (cpb_cnt_minus1 + 1) +#define MAX_NUM_LAYER_IDS 64 + +#define COEF_REMAIN_BIN_REDUCTION 3 ///< indicates the level at which the VLC + ///< transitions from Golomb-Rice to TU+EG(k) + +#define CU_DQP_TU_CMAX 5 ///< max number bins for truncated unary +#define CU_DQP_EG_k 0 ///< expgolomb order + +#define SBH_THRESHOLD 4 ///< I0156: value of the fixed SBH controlling threshold + +#define DISABLING_CLIP_FOR_BIPREDME 1 ///< Ticket #175 + +#define C1FLAG_NUMBER 8 // maximum number of largerThan1 flag coded in one chunk : 16 in HM5 +#define C2FLAG_NUMBER 1 // maximum number of largerThan2 flag coded in one chunk: 16 in HM5 + +#define SAO_ENCODING_CHOICE 1 ///< I0184: picture early termination +#if SAO_ENCODING_CHOICE +#define SAO_ENCODING_RATE 0.75 +#define SAO_ENCODING_CHOICE_CHROMA 1 ///< J0044: picture early termination Luma and Chroma are handled separately +#if SAO_ENCODING_CHOICE_CHROMA +#define SAO_ENCODING_RATE_CHROMA 0.5 +#endif +#endif + +#define MAX_NUM_SAO_OFFSETS 4 + +#define MAX_NUM_VPS 16 +#define MAX_NUM_SPS 16 +#define MAX_NUM_PPS 64 + +#define RDOQ_CHROMA_LAMBDA 1 ///< F386: weighting of chroma for RDOQ + +#define MIN_SCAN_POS_CROSS 4 + +#define FAST_BIT_EST 1 ///< G763: Table-based bit estimation for CABAC + +#define MLS_GRP_NUM 64 ///< G644 : Max number of coefficient groups, max(16, 64) +#define MLS_CG_LOG2_WIDTH 2 +#define MLS_CG_LOG2_HEIGHT 2 +#define MLS_CG_SIZE (MLS_CG_LOG2_WIDTH + MLS_CG_LOG2_HEIGHT) ///< G644 : Coefficient group size of 4x4 + +#define ADAPTIVE_QP_SELECTION 1 ///< G382: Adaptive reconstruction levels, non-normative part for adaptive QP selection +#if ADAPTIVE_QP_SELECTION +#define ARL_C_PRECISION 7 ///< G382: 7-bit arithmetic precision +#define LEVEL_RANGE 30 ///< G382: max coefficient level in statistics collection +#endif + +#define HHI_RQT_INTRA_SPEEDUP 1 ///< tests one best mode with full rqt +#define HHI_RQT_INTRA_SPEEDUP_MOD 0 ///< tests two best modes with full rqt + +#if HHI_RQT_INTRA_SPEEDUP_MOD && !HHI_RQT_INTRA_SPEEDUP +#error +#endif + +#define VERBOSE_RATE 0 ///< Print additional rate information in encoder + +#define AMVP_DECIMATION_FACTOR 4 + +#define SCAN_SET_SIZE 16 +#define LOG2_SCAN_SET_SIZE 4 + +#define FAST_UDI_MAX_RDMODE_NUM 35 ///< maximum number of RD comparison in fast-UDI estimation loop + +#define NUM_INTRA_MODE 36 + +#define WRITE_BACK 1 ///< Enable/disable the encoder to replace the deltaPOC and Used by current from the config file with the values derived by the refIdc parameter. +#define AUTO_INTER_RPS 1 ///< Enable/disable the automatic generation of refIdc from the deltaPOC and Used by current from the config file. +#define PRINT_RPS_INFO 0 ///< Enable/disable the printing of bits used to send the RPS. + // using one nearest frame as reference frame, and the other frames are high quality (POC%4==0) frames (1+X) + // this should be done with encoder only decision + // but because of the absence of reference frame management, the related code was hard coded currently + +#define RVM_VCEGAM10_M 4 + +#define PLANAR_IDX 0 +#define VER_IDX 26 // index for intra VERTICAL mode +#define HOR_IDX 10 // index for intra HORIZONTAL mode +#define DC_IDX 1 // index for intra DC mode +#define NUM_CHROMA_MODE 5 // total number of chroma modes +#define DM_CHROMA_IDX 36 // chroma mode index for derived from luma intra mode +#define INVALID_MODE_IDX (NUM_INTRA_MODE+1) // value used to indicate an invalid intra mode +#define STOPCHROMASEARCH_MODE_IDX (INVALID_MODE_IDX+1) // value used to signal the end of a chroma mode search + +#define MDCS_ANGLE_LIMIT 4 ///< (default 4) 0 = Horizontal/vertical only, 1 = Horizontal/vertical +/- 1, 2 = Horizontal/vertical +/- 2 etc... +#define MDCS_MAXIMUM_WIDTH 8 ///< (default 8) (measured in pixels) TUs with width greater than this can only use diagonal scan +#define MDCS_MAXIMUM_HEIGHT 8 ///< (default 8) (measured in pixels) TUs with height greater than this can only use diagonal scan + +#define FAST_UDI_USE_MPM 1 + +#define RDO_WITHOUT_DQP_BITS 0 ///< Disable counting dQP bits in RDO-based mode decision + +#define LOG2_MAX_NUM_COLUMNS_MINUS1 7 +#define LOG2_MAX_NUM_ROWS_MINUS1 7 +#define LOG2_MAX_COLUMN_WIDTH 13 +#define LOG2_MAX_ROW_HEIGHT 13 + +#define MATRIX_MULT 0 // Brute force matrix multiplication instead of partial butterfly + +#define AMP_SAD 1 ///< dedicated SAD functions for AMP +#define AMP_ENC_SPEEDUP 1 ///< encoder only speed-up by AMP mode skipping +#if AMP_ENC_SPEEDUP +#define AMP_MRG 1 ///< encoder only force merge for AMP partition (no motion search for AMP) +#endif + +#define CABAC_INIT_PRESENT_FLAG 1 + +#define LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS 4 +#define CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS 8 + +#define MAX_NUM_LONG_TERM_REF_PICS 33 + +#define DECODER_CHECK_SUBSTREAM_AND_SLICE_TRAILING_BYTES 1 + +#define RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL 0 ///< 1 = tests whether SAO should be disabled at the picture level, 0 (default) = does not apply this additional test + +#define O0043_BEST_EFFORT_DECODING 0 ///< 0 (default) = disable code related to best effort decoding, 1 = enable code relating to best effort decoding [ decode-side only ]. + +// Cost mode support + +#define LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP 0 ///< QP to use for lossless coding. +#define LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME 4 ///< QP' to use for mixed_lossy_lossless coding. + +// Debug support + +#define ENVIRONMENT_VARIABLE_DEBUG_AND_TEST 0 ///< When enabled, allows control of debug modifications via environment variables + +#define PRINT_MACRO_VALUES 1 ///< When enabled, the encoder prints out a list of the non-environment-variable controlled macros and their values on startup + +// TODO: rename this macro to DECODER_DEBUG_BIT_STATISTICS (may currently cause merge issues with other branches) +// This can be enabled by the makefile +#ifndef RExt__DECODER_DEBUG_BIT_STATISTICS +#define RExt__DECODER_DEBUG_BIT_STATISTICS 0 ///< 0 (default) = decoder reports as normal, 1 = decoder produces bit usage statistics (will impact decoder run time by up to ~10%) +#endif + +// This can be enabled by the makefile +#ifndef RExt__HIGH_BIT_DEPTH_SUPPORT +#define RExt__HIGH_BIT_DEPTH_SUPPORT 0 ///< 0 (default) use data type definitions for 8-10 bit video, 1 = use larger data types to allow for up to 16-bit video (originally developed as part of N0188) +#endif + +#define RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS 4 +#define RExt__GOLOMB_RICE_INCREMENT_DIVISOR 4 + +#define RExt__PREDICTION_WEIGHTING_ANALYSIS_DC_PRECISION 0 ///< Additional fixed bit precision used during encoder-side weighting prediction analysis. Currently only used when high_precision_prediction_weighting_flag is set, for backwards compatibility reasons. + +#define MAX_TIMECODE_SEI_SETS 3 ///< Maximum number of time sets + + +//------------------------------------------------ +// Derived macros +//------------------------------------------------ + +#if RExt__HIGH_BIT_DEPTH_SUPPORT +#define FULL_NBIT 1 ///< When enabled, use distortion measure derived from all bits of source data, otherwise discard (bitDepth - 8) least-significant bits of distortion +#define RExt__HIGH_PRECISION_FORWARD_TRANSFORM 1 ///< 0 use original 6-bit transform matrices for both forward and inverse transform, 1 (default) = use original matrices for inverse transform and high precision matrices for forward transform +#else +#define FULL_NBIT 0 ///< When enabled, use distortion measure derived from all bits of source data, otherwise discard (bitDepth - 8) least-significant bits of distortion +#define RExt__HIGH_PRECISION_FORWARD_TRANSFORM 0 ///< 0 (default) use original 6-bit transform matrices for both forward and inverse transform, 1 = use original matrices for inverse transform and high precision matrices for forward transform +#endif + +#if FULL_NBIT +# define DISTORTION_PRECISION_ADJUSTMENT(x) 0 +#else +# define DISTORTION_PRECISION_ADJUSTMENT(x) (x) +#endif + + +//------------------------------------------------ +// Error checks +//------------------------------------------------ + +#if ((RExt__HIGH_PRECISION_FORWARD_TRANSFORM != 0) && (RExt__HIGH_BIT_DEPTH_SUPPORT == 0)) +#error ERROR: cannot enable RExt__HIGH_PRECISION_FORWARD_TRANSFORM without RExt__HIGH_BIT_DEPTH_SUPPORT +#endif + +// ==================================================================================================================== +// Basic type redefinition +// ==================================================================================================================== + +typedef void Void; +typedef bool Bool; + +#ifdef __arm__ +typedef signed char Char; +#else +typedef char Char; +#endif +typedef unsigned char UChar; +typedef short Short; +typedef unsigned short UShort; +typedef int Int; +typedef unsigned int UInt; +typedef double Double; +typedef float Float; + + +// ==================================================================================================================== +// 64-bit integer type +// ==================================================================================================================== + +#ifdef _MSC_VER +typedef __int64 Int64; + +#if _MSC_VER <= 1200 // MS VC6 +typedef __int64 UInt64; // MS VC6 does not support unsigned __int64 to double conversion +#else +typedef unsigned __int64 UInt64; +#endif + +#else + +typedef long long Int64; +typedef unsigned long long UInt64; + +#endif + + +// ==================================================================================================================== +// Enumeration +// ==================================================================================================================== + +enum RDPCMMode +{ + RDPCM_OFF = 0, + RDPCM_HOR = 1, + RDPCM_VER = 2, + NUMBER_OF_RDPCM_MODES = 3 +}; + +enum RDPCMSignallingMode +{ + RDPCM_SIGNAL_IMPLICIT = 0, + RDPCM_SIGNAL_EXPLICIT = 1, + NUMBER_OF_RDPCM_SIGNALLING_MODES = 2 +}; + +/// supported slice type +enum SliceType +{ + B_SLICE = 0, + P_SLICE = 1, + I_SLICE = 2, + NUMBER_OF_SLICE_TYPES = 3 +}; + +/// chroma formats (according to semantics of chroma_format_idc) +enum ChromaFormat +{ + CHROMA_400 = 0, + CHROMA_420 = 1, + CHROMA_422 = 2, + CHROMA_444 = 3, + NUM_CHROMA_FORMAT = 4 +}; + +enum ChannelType +{ + CHANNEL_TYPE_LUMA = 0, + CHANNEL_TYPE_CHROMA = 1, + MAX_NUM_CHANNEL_TYPE = 2 +}; + +enum ComponentID +{ + COMPONENT_Y = 0, + COMPONENT_Cb = 1, + COMPONENT_Cr = 2, + MAX_NUM_COMPONENT = 3 +}; + +enum InputColourSpaceConversion // defined in terms of conversion prior to input of encoder. +{ + IPCOLOURSPACE_UNCHANGED = 0, + IPCOLOURSPACE_YCbCrtoYCrCb = 1, // Mainly used for debug! + IPCOLOURSPACE_YCbCrtoYYY = 2, // Mainly used for debug! + IPCOLOURSPACE_RGBtoGBR = 3, + NUMBER_INPUT_COLOUR_SPACE_CONVERSIONS = 4 +}; + +enum DeblockEdgeDir +{ + EDGE_VER = 0, + EDGE_HOR = 1, + NUM_EDGE_DIR = 2 +}; + +/// supported partition shape +enum PartSize +{ + SIZE_2Nx2N = 0, ///< symmetric motion partition, 2Nx2N + SIZE_2NxN = 1, ///< symmetric motion partition, 2Nx N + SIZE_Nx2N = 2, ///< symmetric motion partition, Nx2N + SIZE_NxN = 3, ///< symmetric motion partition, Nx N + SIZE_2NxnU = 4, ///< asymmetric motion partition, 2Nx( N/2) + 2Nx(3N/2) + SIZE_2NxnD = 5, ///< asymmetric motion partition, 2Nx(3N/2) + 2Nx( N/2) + SIZE_nLx2N = 6, ///< asymmetric motion partition, ( N/2)x2N + (3N/2)x2N + SIZE_nRx2N = 7, ///< asymmetric motion partition, (3N/2)x2N + ( N/2)x2N + NUMBER_OF_PART_SIZES = 8 +}; + +/// supported prediction type +enum PredMode +{ + MODE_INTER = 0, ///< inter-prediction mode + MODE_INTRA = 1, ///< intra-prediction mode + NUMBER_OF_PREDICTION_MODES = 2, +}; + +/// reference list index +enum RefPicList +{ + REF_PIC_LIST_0 = 0, ///< reference list 0 + REF_PIC_LIST_1 = 1, ///< reference list 1 + NUM_REF_PIC_LIST_01 = 2, + REF_PIC_LIST_X = 100 ///< special mark +}; + +/// distortion function index +enum DFunc +{ + DF_DEFAULT = 0, + DF_SSE = 1, ///< general size SSE + DF_SSE4 = 2, ///< 4xM SSE + DF_SSE8 = 3, ///< 8xM SSE + DF_SSE16 = 4, ///< 16xM SSE + DF_SSE32 = 5, ///< 32xM SSE + DF_SSE64 = 6, ///< 64xM SSE + DF_SSE16N = 7, ///< 16NxM SSE + + DF_SAD = 8, ///< general size SAD + DF_SAD4 = 9, ///< 4xM SAD + DF_SAD8 = 10, ///< 8xM SAD + DF_SAD16 = 11, ///< 16xM SAD + DF_SAD32 = 12, ///< 32xM SAD + DF_SAD64 = 13, ///< 64xM SAD + DF_SAD16N = 14, ///< 16NxM SAD + + DF_SADS = 15, ///< general size SAD with step + DF_SADS4 = 16, ///< 4xM SAD with step + DF_SADS8 = 17, ///< 8xM SAD with step + DF_SADS16 = 18, ///< 16xM SAD with step + DF_SADS32 = 19, ///< 32xM SAD with step + DF_SADS64 = 20, ///< 64xM SAD with step + DF_SADS16N = 21, ///< 16NxM SAD with step + + DF_HADS = 22, ///< general size Hadamard with step + DF_HADS4 = 23, ///< 4xM HAD with step + DF_HADS8 = 24, ///< 8xM HAD with step + DF_HADS16 = 25, ///< 16xM HAD with step + DF_HADS32 = 26, ///< 32xM HAD with step + DF_HADS64 = 27, ///< 64xM HAD with step + DF_HADS16N = 28, ///< 16NxM HAD with step + +#if AMP_SAD + DF_SAD12 = 43, + DF_SAD24 = 44, + DF_SAD48 = 45, + + DF_SADS12 = 46, + DF_SADS24 = 47, + DF_SADS48 = 48, + + DF_SSE_FRAME = 50, ///< Frame-based SSE + DF_TOTAL_FUNCTIONS = 64 +#else + DF_SSE_FRAME = 32, ///< Frame-based SSE + DF_TOTAL_FUNCTIONS = 33 +#endif +}; + +/// index for SBAC based RD optimization +enum CI_IDX +{ + CI_CURR_BEST = 0, ///< best mode index + CI_NEXT_BEST, ///< next best index + CI_TEMP_BEST, ///< temporal index + CI_CHROMA_INTRA, ///< chroma intra index + CI_QT_TRAFO_TEST, + CI_QT_TRAFO_ROOT, + CI_NUM, ///< total number +}; + +/// motion vector predictor direction used in AMVP +enum MVP_DIR +{ + MD_LEFT = 0, ///< MVP of left block + MD_ABOVE, ///< MVP of above block + MD_ABOVE_RIGHT, ///< MVP of above right block + MD_BELOW_LEFT, ///< MVP of below left block + MD_ABOVE_LEFT ///< MVP of above left block +}; + +enum StoredResidualType +{ + RESIDUAL_RECONSTRUCTED = 0, + RESIDUAL_ENCODER_SIDE = 1, + NUMBER_OF_STORED_RESIDUAL_TYPES = 2 +}; + +enum TransformDirection +{ + TRANSFORM_FORWARD = 0, + TRANSFORM_INVERSE = 1, + TRANSFORM_NUMBER_OF_DIRECTIONS = 2 +}; + +/// supported ME search methods +enum MESearchMethod +{ + FULL_SEARCH = 0, ///< Full search + DIAMOND = 1, ///< Fast search + SELECTIVE = 2 ///< Selective search +}; + +/// coefficient scanning type used in ACS +enum COEFF_SCAN_TYPE +{ + SCAN_DIAG = 0, ///< up-right diagonal scan + SCAN_HOR = 1, ///< horizontal first scan + SCAN_VER = 2, ///< vertical first scan + SCAN_NUMBER_OF_TYPES = 3 +}; + +enum COEFF_SCAN_GROUP_TYPE +{ + SCAN_UNGROUPED = 0, + SCAN_GROUPED_4x4 = 1, + SCAN_NUMBER_OF_GROUP_TYPES = 2 +}; + +enum SignificanceMapContextType +{ + CONTEXT_TYPE_4x4 = 0, + CONTEXT_TYPE_8x8 = 1, + CONTEXT_TYPE_NxN = 2, + CONTEXT_TYPE_SINGLE = 3, + CONTEXT_NUMBER_OF_TYPES = 4 +}; + +enum ScalingListMode +{ + SCALING_LIST_OFF, + SCALING_LIST_DEFAULT, + SCALING_LIST_FILE_READ +}; + +enum ScalingListSize +{ + SCALING_LIST_4x4 = 0, + SCALING_LIST_8x8, + SCALING_LIST_16x16, + SCALING_LIST_32x32, + SCALING_LIST_SIZE_NUM +}; + +// Slice / Slice segment encoding modes +enum SliceConstraint +{ + NO_SLICES = 0, ///< don't use slices / slice segments + FIXED_NUMBER_OF_CTU = 1, ///< Limit maximum number of largest coding tree units in a slice / slice segments + FIXED_NUMBER_OF_BYTES = 2, ///< Limit maximum number of bytes in a slice / slice segment + FIXED_NUMBER_OF_TILES = 3, ///< slices / slice segments span an integer number of tiles +}; + +enum SAOMode //mode +{ + SAO_MODE_OFF = 0, + SAO_MODE_NEW, + SAO_MODE_MERGE, + NUM_SAO_MODES +}; + +enum SAOModeMergeTypes +{ + SAO_MERGE_LEFT =0, + SAO_MERGE_ABOVE, + NUM_SAO_MERGE_TYPES +}; + + +enum SAOModeNewTypes +{ + SAO_TYPE_START_EO =0, + SAO_TYPE_EO_0 = SAO_TYPE_START_EO, + SAO_TYPE_EO_90, + SAO_TYPE_EO_135, + SAO_TYPE_EO_45, + + SAO_TYPE_START_BO, + SAO_TYPE_BO = SAO_TYPE_START_BO, + + NUM_SAO_NEW_TYPES +}; +#define NUM_SAO_EO_TYPES_LOG2 2 + +enum SAOEOClasses +{ + SAO_CLASS_EO_FULL_VALLEY = 0, + SAO_CLASS_EO_HALF_VALLEY = 1, + SAO_CLASS_EO_PLAIN = 2, + SAO_CLASS_EO_HALF_PEAK = 3, + SAO_CLASS_EO_FULL_PEAK = 4, + NUM_SAO_EO_CLASSES, +}; + +#define NUM_SAO_BO_CLASSES_LOG2 5 +#define NUM_SAO_BO_CLASSES (1< NUM_SAO_BO_GROUPS)?NUM_SAO_EO_GROUPS:NUM_SAO_BO_GROUPS + +struct SAOOffset +{ + SAOMode modeIdc; // NEW, MERGE, OFF + Int typeIdc; // union of SAOModeMergeTypes and SAOModeNewTypes, depending on modeIdc. + Int typeAuxInfo; // BO: starting band index + Int offset[MAX_NUM_SAO_CLASSES]; + + SAOOffset(); + ~SAOOffset(); + Void reset(); + + const SAOOffset& operator= (const SAOOffset& src); +}; + +struct SAOBlkParam +{ + + SAOBlkParam(); + ~SAOBlkParam(); + Void reset(); + const SAOBlkParam& operator= (const SAOBlkParam& src); + SAOOffset& operator[](Int compIdx){ return offsetParam[compIdx];} +private: + SAOOffset offsetParam[MAX_NUM_COMPONENT]; + +}; + + +/// parameters for deblocking filter +typedef struct _LFCUParam +{ + Bool bInternalEdge; ///< indicates internal edge + Bool bLeftEdge; ///< indicates left edge + Bool bTopEdge; ///< indicates top edge +} LFCUParam; + + + +//TU settings for entropy encoding +struct TUEntropyCodingParameters +{ + const UInt *scan; + const UInt *scanCG; + COEFF_SCAN_TYPE scanType; + UInt widthInGroups; + UInt heightInGroups; + UInt firstSignificanceMapContext; +}; + + +struct TComDigest +{ + std::vector hash; + + Bool operator==(const TComDigest &other) const + { + if (other.hash.size() != hash.size()) return false; + for(UInt i=0; i +#include "TLibCommon/AccessUnit.h" +#include "NALwrite.h" + +//! \ingroup TLibEncoder +//! \{ + +/** + * write all NALunits in au to bytestream out in a manner satisfying + * AnnexB of AVC. NALunits are written in the order they are found in au. + * the zero_byte word is appended to: + * - the initial startcode in the access unit, + * - any SPS/PPS nal units + */ +static std::vector writeAnnexB(std::ostream& out, const AccessUnit& au) +{ + std::vector annexBsizes; + + for (AccessUnit::const_iterator it = au.begin(); it != au.end(); it++) + { + const NALUnitEBSP& nalu = **it; + UInt size = 0; /* size of annexB unit in bytes */ + + static const Char start_code_prefix[] = {0,0,0,1}; + if (it == au.begin() || nalu.m_nalUnitType == NAL_UNIT_VPS || nalu.m_nalUnitType == NAL_UNIT_SPS || nalu.m_nalUnitType == NAL_UNIT_PPS) + { + /* From AVC, When any of the following conditions are fulfilled, the + * zero_byte syntax element shall be present: + * - the nal_unit_type within the nal_unit() is equal to 7 (sequence + * parameter set) or 8 (picture parameter set), + * - the byte stream NAL unit syntax structure contains the first NAL + * unit of an access unit in decoding order, as specified by subclause + * 7.4.1.2.3. + */ + out.write(start_code_prefix, 4); + size += 4; + } + else + { + out.write(start_code_prefix+1, 3); + size += 3; + } + out << nalu.m_nalUnitData.str(); + size += UInt(nalu.m_nalUnitData.str().size()); + + annexBsizes.push_back(size); + } + + return annexBsizes; +} +//! \} + +#endif diff --git a/jctvc/TLibEncoder/NALwrite.cpp b/jctvc/TLibEncoder/NALwrite.cpp new file mode 100644 index 0000000..ef9f7b5 --- /dev/null +++ b/jctvc/TLibEncoder/NALwrite.cpp @@ -0,0 +1,123 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "TLibCommon/NAL.h" +#include "TLibCommon/TComBitStream.h" +#include "NALwrite.h" + +using namespace std; + +//! \ingroup TLibEncoder +//! \{ + +static const Char emulation_prevention_three_byte[] = {3}; + +Void writeNalUnitHeader(ostream& out, OutputNALUnit& nalu) // nal_unit_header() +{ +TComOutputBitstream bsNALUHeader; + + bsNALUHeader.write(0,1); // forbidden_zero_bit + bsNALUHeader.write(nalu.m_nalUnitType, 6); // nal_unit_type + bsNALUHeader.write(nalu.m_reservedZero6Bits, 6); // nuh_reserved_zero_6bits + bsNALUHeader.write(nalu.m_temporalId+1, 3); // nuh_temporal_id_plus1 + + out.write(bsNALUHeader.getByteStream(), bsNALUHeader.getByteStreamLength()); +} +/** + * write nalu to bytestream out, performing RBSP anti startcode + * emulation as required. nalu.m_RBSPayload must be byte aligned. + */ +Void write(ostream& out, OutputNALUnit& nalu) +{ + writeNalUnitHeader(out, nalu); + /* write out rsbp_byte's, inserting any required + * emulation_prevention_three_byte's */ + /* 7.4.1 ... + * emulation_prevention_three_byte is a byte equal to 0x03. When an + * emulation_prevention_three_byte is present in the NAL unit, it shall be + * discarded by the decoding process. + * The last byte of the NAL unit shall not be equal to 0x00. + * Within the NAL unit, the following three-byte sequences shall not occur at + * any byte-aligned position: + * - 0x000000 + * - 0x000001 + * - 0x000002 + * Within the NAL unit, any four-byte sequence that starts with 0x000003 + * other than the following sequences shall not occur at any byte-aligned + * position: + * - 0x00000300 + * - 0x00000301 + * - 0x00000302 + * - 0x00000303 + */ + vector& rbsp = nalu.m_Bitstream.getFIFO(); + + vector outputBuffer; + outputBuffer.resize(rbsp.size()*2+1); //there can never be enough emulation_prevention_three_bytes to require this much space + std::size_t outputAmount = 0; + Int zeroCount = 0; + for (vector::iterator it = rbsp.begin(); it != rbsp.end(); it++) + { + const uint8_t v=(*it); + if (zeroCount==2 && v<=3) + { + outputBuffer[outputAmount++]=emulation_prevention_three_byte[0]; + zeroCount=0; + } + if (v==0) zeroCount++; else zeroCount=0; + outputBuffer[outputAmount++]=v; + } + + /* 7.4.1.1 + * ... when the last byte of the RBSP data is equal to 0x00 (which can + * only occur when the RBSP ends in a cabac_zero_word), a final byte equal + * to 0x03 is appended to the end of the data. + */ + if (zeroCount>0) outputBuffer[outputAmount++]=emulation_prevention_three_byte[0]; + out.write((Char*)&(*outputBuffer.begin()), outputAmount); +} + +/** + * Write rbsp_trailing_bits to bs causing it to become byte-aligned + */ +Void writeRBSPTrailingBits(TComOutputBitstream& bs) +{ + bs.write( 1, 1 ); + bs.writeAlignZero(); +} + +//! \} diff --git a/jctvc/TLibEncoder/NALwrite.h b/jctvc/TLibEncoder/NALwrite.h new file mode 100644 index 0000000..09d8ed7 --- /dev/null +++ b/jctvc/TLibEncoder/NALwrite.h @@ -0,0 +1,88 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#ifndef __NALWRITE__ +#define __NALWRITE__ + +#include + +#include "TLibCommon/TypeDef.h" +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/NAL.h" + +//! \ingroup TLibEncoder +//! \{ + +/** + * A convenience wrapper to NALUnit that also provides a + * bitstream object. + */ +struct OutputNALUnit : public NALUnit +{ + /** + * construct an OutputNALunit structure with given header values and + * storage for a bitstream. Upon construction the NALunit header is + * written to the bitstream. + */ + OutputNALUnit( + NalUnitType nalUnitType, + UInt temporalID = 0, + UInt reserved_zero_6bits = 0) + : NALUnit(nalUnitType, temporalID, reserved_zero_6bits) + , m_Bitstream() + {} + + OutputNALUnit& operator=(const NALUnit& src) + { + m_Bitstream.clear(); + static_cast(this)->operator=(src); + return *this; + } + + TComOutputBitstream m_Bitstream; +}; + +Void write(std::ostream& out, OutputNALUnit& nalu); +Void writeRBSPTrailingBits(TComOutputBitstream& bs); + +inline NALUnitEBSP::NALUnitEBSP(OutputNALUnit& nalu) + : NALUnit(nalu) +{ + write(m_nalUnitData, nalu); +} + +//! \} + +#endif diff --git a/jctvc/TLibEncoder/SEIwrite.cpp b/jctvc/TLibEncoder/SEIwrite.cpp new file mode 100644 index 0000000..aeca8cc --- /dev/null +++ b/jctvc/TLibEncoder/SEIwrite.cpp @@ -0,0 +1,791 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TLibCommon/TComBitCounter.h" +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/SEI.h" +#include "TLibCommon/TComSlice.h" +#include "TLibCommon/TComPicYuv.h" +#include "SEIwrite.h" + +//! \ingroup TLibEncoder +//! \{ + +#if ENC_DEC_TRACE +Void xTraceSEIHeader() +{ + fprintf( g_hTrace, "=========== SEI message ===========\n"); +} + +Void xTraceSEIMessageType(SEI::PayloadType payloadType) +{ + fprintf( g_hTrace, "=========== %s SEI message ===========\n", SEI::getSEIMessageString(payloadType)); +} +#endif + +Void SEIWriter::xWriteSEIpayloadData(TComBitIf& bs, const SEI& sei, TComSPS *sps) +{ + switch (sei.payloadType()) + { + case SEI::USER_DATA_UNREGISTERED: + xWriteSEIuserDataUnregistered(*static_cast(&sei)); + break; + case SEI::ACTIVE_PARAMETER_SETS: + xWriteSEIActiveParameterSets(*static_cast(& sei)); + break; + case SEI::DECODING_UNIT_INFO: + xWriteSEIDecodingUnitInfo(*static_cast(& sei), sps); + break; + case SEI::DECODED_PICTURE_HASH: + xWriteSEIDecodedPictureHash(*static_cast(&sei)); + break; + case SEI::BUFFERING_PERIOD: + xWriteSEIBufferingPeriod(*static_cast(&sei), sps); + break; + case SEI::PICTURE_TIMING: + xWriteSEIPictureTiming(*static_cast(&sei), sps); + break; + case SEI::RECOVERY_POINT: + xWriteSEIRecoveryPoint(*static_cast(&sei)); + break; + case SEI::FRAME_PACKING: + xWriteSEIFramePacking(*static_cast(&sei)); + break; + case SEI::SEGM_RECT_FRAME_PACKING: + xWriteSEISegmentedRectFramePacking(*static_cast(&sei)); + break; + case SEI::DISPLAY_ORIENTATION: + xWriteSEIDisplayOrientation(*static_cast(&sei)); + break; + case SEI::TEMPORAL_LEVEL0_INDEX: + xWriteSEITemporalLevel0Index(*static_cast(&sei)); + break; + case SEI::REGION_REFRESH_INFO: + xWriteSEIGradualDecodingRefreshInfo(*static_cast(&sei)); + break; + case SEI::NO_DISPLAY: + xWriteSEINoDisplay(*static_cast(&sei)); + break; + case SEI::TONE_MAPPING_INFO: + xWriteSEIToneMappingInfo(*static_cast(&sei)); + break; + case SEI::SOP_DESCRIPTION: + xWriteSEISOPDescription(*static_cast(&sei)); + break; + case SEI::SCALABLE_NESTING: + xWriteSEIScalableNesting(bs, *static_cast(&sei), sps); + break; + case SEI::CHROMA_SAMPLING_FILTER_HINT: + xWriteSEIChromaSamplingFilterHint(*static_cast(&sei)/*, sps*/); + break; + case SEI::TEMP_MOTION_CONSTRAINED_TILE_SETS: + xWriteSEITempMotionConstrainedTileSets(bs, *static_cast(&sei)); + break; + case SEI::TIME_CODE: + xWriteSEITimeCode(*static_cast(&sei)); + break; + case SEI::KNEE_FUNCTION_INFO: + xWriteSEIKneeFunctionInfo(*static_cast(&sei)); + break; + case SEI::MASTERING_DISPLAY_COLOUR_VOLUME: + xWriteSEIMasteringDisplayColourVolume(*static_cast(&sei)); + break; + default: + assert(!"Unhandled SEI message"); + break; + } + xWriteByteAlign(); +} + +/** + * marshal a single SEI message sei, storing the marshalled representation + * in bitstream bs. + */ +Void SEIWriter::writeSEImessage(TComBitIf& bs, const SEI& sei, TComSPS *sps) +{ + /* calculate how large the payload data is */ + /* TODO: this would be far nicer if it used vectored buffers */ + TComBitCounter bs_count; + bs_count.resetBits(); + setBitstream(&bs_count); + + +#if ENC_DEC_TRACE + Bool traceEnable = g_HLSTraceEnable; + g_HLSTraceEnable = false; +#endif + xWriteSEIpayloadData(bs_count, sei, sps); +#if ENC_DEC_TRACE + g_HLSTraceEnable = traceEnable; +#endif + + UInt payload_data_num_bits = bs_count.getNumberOfWrittenBits(); + assert(0 == payload_data_num_bits % 8); + + setBitstream(&bs); + +#if ENC_DEC_TRACE + if (g_HLSTraceEnable) + xTraceSEIHeader(); +#endif + + UInt payloadType = sei.payloadType(); + for (; payloadType >= 0xff; payloadType -= 0xff) + { + WRITE_CODE(0xff, 8, "payload_type"); + } + WRITE_CODE(payloadType, 8, "payload_type"); + + UInt payloadSize = payload_data_num_bits/8; + for (; payloadSize >= 0xff; payloadSize -= 0xff) + { + WRITE_CODE(0xff, 8, "payload_size"); + } + WRITE_CODE(payloadSize, 8, "payload_size"); + + /* payloadData */ +#if ENC_DEC_TRACE + if (g_HLSTraceEnable) + xTraceSEIMessageType(sei.payloadType()); +#endif + + xWriteSEIpayloadData(bs, sei, sps); +} + +/** + * marshal a user_data_unregistered SEI message sei, storing the marshalled + * representation in bitstream bs. + */ +Void SEIWriter::xWriteSEIuserDataUnregistered(const SEIuserDataUnregistered &sei) +{ + for (UInt i = 0; i < ISO_IEC_11578_LEN; i++) + { + WRITE_CODE(sei.uuid_iso_iec_11578[i], 8 , "sei.uuid_iso_iec_11578[i]"); + } + + for (UInt i = 0; i < sei.userDataLength; i++) + { + WRITE_CODE(sei.userData[i], 8 , "user_data"); + } +} + +/** + * marshal a decoded picture hash SEI message, storing the marshalled + * representation in bitstream bs. + */ +Void SEIWriter::xWriteSEIDecodedPictureHash(const SEIDecodedPictureHash& sei) +{ + const Char *traceString="\0"; + switch (sei.method) + { + case SEIDecodedPictureHash::MD5: traceString="picture_md5"; break; + case SEIDecodedPictureHash::CRC: traceString="picture_crc"; break; + case SEIDecodedPictureHash::CHECKSUM: traceString="picture_checksum"; break; + default: assert(false); break; + } + + if (traceString != 0) //use of this variable is needed to avoid a compiler error with G++ 4.6.1 + { + WRITE_CODE(sei.method, 8, "hash_type"); + for(UInt i=0; igetVuiParameters(); + WRITE_UVLC(sei.m_decodingUnitIdx, "decoding_unit_idx"); + if(vui->getHrdParameters()->getSubPicCpbParamsInPicTimingSEIFlag()) + { + WRITE_CODE( sei.m_duSptCpbRemovalDelay, (vui->getHrdParameters()->getDuCpbRemovalDelayLengthMinus1() + 1), "du_spt_cpb_removal_delay"); + } + WRITE_FLAG( sei.m_dpbOutputDuDelayPresentFlag, "dpb_output_du_delay_present_flag"); + if(sei.m_dpbOutputDuDelayPresentFlag) + { + WRITE_CODE(sei.m_picSptDpbOutputDuDelay, vui->getHrdParameters()->getDpbOutputDelayDuLengthMinus1() + 1, "pic_spt_dpb_output_du_delay"); + } +} + +Void SEIWriter::xWriteSEIBufferingPeriod(const SEIBufferingPeriod& sei, TComSPS *sps) +{ + Int i, nalOrVcl; + TComVUI *vui = sps->getVuiParameters(); + TComHRD *hrd = vui->getHrdParameters(); + + WRITE_UVLC( sei.m_bpSeqParameterSetId, "bp_seq_parameter_set_id" ); + if( !hrd->getSubPicCpbParamsPresentFlag() ) + { + WRITE_FLAG( sei.m_rapCpbParamsPresentFlag, "irap_cpb_params_present_flag" ); + } + if( sei.m_rapCpbParamsPresentFlag ) + { + WRITE_CODE( sei.m_cpbDelayOffset, hrd->getCpbRemovalDelayLengthMinus1() + 1, "cpb_delay_offset" ); + WRITE_CODE( sei.m_dpbDelayOffset, hrd->getDpbOutputDelayLengthMinus1() + 1, "dpb_delay_offset" ); + } + WRITE_FLAG( sei.m_concatenationFlag, "concatenation_flag"); + WRITE_CODE( sei.m_auCpbRemovalDelayDelta - 1, ( hrd->getCpbRemovalDelayLengthMinus1() + 1 ), "au_cpb_removal_delay_delta_minus1" ); + for( nalOrVcl = 0; nalOrVcl < 2; nalOrVcl ++ ) + { + if( ( ( nalOrVcl == 0 ) && ( hrd->getNalHrdParametersPresentFlag() ) ) || + ( ( nalOrVcl == 1 ) && ( hrd->getVclHrdParametersPresentFlag() ) ) ) + { + for( i = 0; i < ( hrd->getCpbCntMinus1( 0 ) + 1 ); i ++ ) + { + WRITE_CODE( sei.m_initialCpbRemovalDelay[i][nalOrVcl],( hrd->getInitialCpbRemovalDelayLengthMinus1() + 1 ) , "initial_cpb_removal_delay" ); + WRITE_CODE( sei.m_initialCpbRemovalDelayOffset[i][nalOrVcl],( hrd->getInitialCpbRemovalDelayLengthMinus1() + 1 ), "initial_cpb_removal_delay_offset" ); + if( hrd->getSubPicCpbParamsPresentFlag() || sei.m_rapCpbParamsPresentFlag ) + { + WRITE_CODE( sei.m_initialAltCpbRemovalDelay[i][nalOrVcl], ( hrd->getInitialCpbRemovalDelayLengthMinus1() + 1 ) , "initial_alt_cpb_removal_delay" ); + WRITE_CODE( sei.m_initialAltCpbRemovalDelayOffset[i][nalOrVcl], ( hrd->getInitialCpbRemovalDelayLengthMinus1() + 1 ),"initial_alt_cpb_removal_delay_offset" ); + } + } + } + } +} +Void SEIWriter::xWriteSEIPictureTiming(const SEIPictureTiming& sei, TComSPS *sps) +{ + Int i; + TComVUI *vui = sps->getVuiParameters(); + TComHRD *hrd = vui->getHrdParameters(); + + if( vui->getFrameFieldInfoPresentFlag() ) + { + WRITE_CODE( sei.m_picStruct, 4, "pic_struct" ); + WRITE_CODE( sei.m_sourceScanType, 2, "source_scan_type" ); + WRITE_FLAG( sei.m_duplicateFlag ? 1 : 0, "duplicate_flag" ); + } + + if( hrd->getCpbDpbDelaysPresentFlag() ) + { + WRITE_CODE( sei.m_auCpbRemovalDelay - 1, ( hrd->getCpbRemovalDelayLengthMinus1() + 1 ), "au_cpb_removal_delay_minus1" ); + WRITE_CODE( sei.m_picDpbOutputDelay, ( hrd->getDpbOutputDelayLengthMinus1() + 1 ), "pic_dpb_output_delay" ); + if(hrd->getSubPicCpbParamsPresentFlag()) + { + WRITE_CODE(sei.m_picDpbOutputDuDelay, hrd->getDpbOutputDelayDuLengthMinus1()+1, "pic_dpb_output_du_delay" ); + } + if( hrd->getSubPicCpbParamsPresentFlag() && hrd->getSubPicCpbParamsInPicTimingSEIFlag() ) + { + WRITE_UVLC( sei.m_numDecodingUnitsMinus1, "num_decoding_units_minus1" ); + WRITE_FLAG( sei.m_duCommonCpbRemovalDelayFlag, "du_common_cpb_removal_delay_flag" ); + if( sei.m_duCommonCpbRemovalDelayFlag ) + { + WRITE_CODE( sei.m_duCommonCpbRemovalDelayMinus1, ( hrd->getDuCpbRemovalDelayLengthMinus1() + 1 ), "du_common_cpb_removal_delay_minus1" ); + } + for( i = 0; i <= sei.m_numDecodingUnitsMinus1; i ++ ) + { + WRITE_UVLC( sei.m_numNalusInDuMinus1[ i ], "num_nalus_in_du_minus1"); + if( ( !sei.m_duCommonCpbRemovalDelayFlag ) && ( i < sei.m_numDecodingUnitsMinus1 ) ) + { + WRITE_CODE( sei.m_duCpbRemovalDelayMinus1[ i ], ( hrd->getDuCpbRemovalDelayLengthMinus1() + 1 ), "du_cpb_removal_delay_minus1" ); + } + } + } + } +} +Void SEIWriter::xWriteSEIRecoveryPoint(const SEIRecoveryPoint& sei) +{ + WRITE_SVLC( sei.m_recoveryPocCnt, "recovery_poc_cnt" ); + WRITE_FLAG( sei.m_exactMatchingFlag, "exact_matching_flag" ); + WRITE_FLAG( sei.m_brokenLinkFlag, "broken_link_flag" ); +} +Void SEIWriter::xWriteSEIFramePacking(const SEIFramePacking& sei) +{ + WRITE_UVLC( sei.m_arrangementId, "frame_packing_arrangement_id" ); + WRITE_FLAG( sei.m_arrangementCancelFlag, "frame_packing_arrangement_cancel_flag" ); + + if( sei.m_arrangementCancelFlag == 0 ) { + WRITE_CODE( sei.m_arrangementType, 7, "frame_packing_arrangement_type" ); + + WRITE_FLAG( sei.m_quincunxSamplingFlag, "quincunx_sampling_flag" ); + WRITE_CODE( sei.m_contentInterpretationType, 6, "content_interpretation_type" ); + WRITE_FLAG( sei.m_spatialFlippingFlag, "spatial_flipping_flag" ); + WRITE_FLAG( sei.m_frame0FlippedFlag, "frame0_flipped_flag" ); + WRITE_FLAG( sei.m_fieldViewsFlag, "field_views_flag" ); + WRITE_FLAG( sei.m_currentFrameIsFrame0Flag, "current_frame_is_frame0_flag" ); + + WRITE_FLAG( sei.m_frame0SelfContainedFlag, "frame0_self_contained_flag" ); + WRITE_FLAG( sei.m_frame1SelfContainedFlag, "frame1_self_contained_flag" ); + + if(sei.m_quincunxSamplingFlag == 0 && sei.m_arrangementType != 5) + { + WRITE_CODE( sei.m_frame0GridPositionX, 4, "frame0_grid_position_x" ); + WRITE_CODE( sei.m_frame0GridPositionY, 4, "frame0_grid_position_y" ); + WRITE_CODE( sei.m_frame1GridPositionX, 4, "frame1_grid_position_x" ); + WRITE_CODE( sei.m_frame1GridPositionY, 4, "frame1_grid_position_y" ); + } + + WRITE_CODE( sei.m_arrangementReservedByte, 8, "frame_packing_arrangement_reserved_byte" ); + WRITE_FLAG( sei.m_arrangementPersistenceFlag, "frame_packing_arrangement_persistence_flag" ); + } + + WRITE_FLAG( sei.m_upsampledAspectRatio, "upsampled_aspect_ratio" ); +} + +Void SEIWriter::xWriteSEISegmentedRectFramePacking(const SEISegmentedRectFramePacking& sei) +{ + WRITE_FLAG( sei.m_arrangementCancelFlag, "segmented_rect_frame_packing_arrangement_cancel_flag" ); + if( sei.m_arrangementCancelFlag == 0 ) + { + WRITE_CODE( sei.m_contentInterpretationType, 2, "segmented_rect_content_interpretation_type" ); + WRITE_FLAG( sei.m_arrangementPersistenceFlag, "segmented_rect_frame_packing_arrangement_persistence" ); + } +} + +Void SEIWriter::xWriteSEIToneMappingInfo(const SEIToneMappingInfo& sei) +{ + Int i; + WRITE_UVLC( sei.m_toneMapId, "tone_map_id" ); + WRITE_FLAG( sei.m_toneMapCancelFlag, "tone_map_cancel_flag" ); + if( !sei.m_toneMapCancelFlag ) + { + WRITE_FLAG( sei.m_toneMapPersistenceFlag, "tone_map_persistence_flag" ); + WRITE_CODE( sei.m_codedDataBitDepth, 8, "coded_data_bit_depth" ); + WRITE_CODE( sei.m_targetBitDepth, 8, "target_bit_depth" ); + WRITE_UVLC( sei.m_modelId, "model_id" ); + switch(sei.m_modelId) + { + case 0: + { + WRITE_CODE( sei.m_minValue, 32, "min_value" ); + WRITE_CODE( sei.m_maxValue, 32, "max_value" ); + break; + } + case 1: + { + WRITE_CODE( sei.m_sigmoidMidpoint, 32, "sigmoid_midpoint" ); + WRITE_CODE( sei.m_sigmoidWidth, 32, "sigmoid_width" ); + break; + } + case 2: + { + UInt num = 1u << sei.m_targetBitDepth; + for(i = 0; i < num; i++) + { + WRITE_CODE( sei.m_startOfCodedInterval[i], (( sei.m_codedDataBitDepth + 7 ) >> 3 ) << 3, "start_of_coded_interval" ); + } + break; + } + case 3: + { + WRITE_CODE( sei.m_numPivots, 16, "num_pivots" ); + for(i = 0; i < sei.m_numPivots; i++ ) + { + WRITE_CODE( sei.m_codedPivotValue[i], (( sei.m_codedDataBitDepth + 7 ) >> 3 ) << 3, "coded_pivot_value" ); + WRITE_CODE( sei.m_targetPivotValue[i], (( sei.m_targetBitDepth + 7 ) >> 3 ) << 3, "target_pivot_value"); + } + break; + } + case 4: + { + WRITE_CODE( sei.m_cameraIsoSpeedIdc, 8, "camera_iso_speed_idc" ); + if( sei.m_cameraIsoSpeedIdc == 255) //Extended_ISO + { + WRITE_CODE( sei.m_cameraIsoSpeedValue, 32, "camera_iso_speed_value" ); + } + WRITE_CODE( sei.m_exposureIndexIdc, 8, "exposure_index_idc" ); + if( sei.m_exposureIndexIdc == 255) //Extended_ISO + { + WRITE_CODE( sei.m_exposureIndexValue, 32, "exposure_index_value" ); + } + WRITE_FLAG( sei.m_exposureCompensationValueSignFlag, "exposure_compensation_value_sign_flag" ); + WRITE_CODE( sei.m_exposureCompensationValueNumerator, 16, "exposure_compensation_value_numerator" ); + WRITE_CODE( sei.m_exposureCompensationValueDenomIdc, 16, "exposure_compensation_value_denom_idc" ); + WRITE_CODE( sei.m_refScreenLuminanceWhite, 32, "ref_screen_luminance_white" ); + WRITE_CODE( sei.m_extendedRangeWhiteLevel, 32, "extended_range_white_level" ); + WRITE_CODE( sei.m_nominalBlackLevelLumaCodeValue, 16, "nominal_black_level_luma_code_value" ); + WRITE_CODE( sei.m_nominalWhiteLevelLumaCodeValue, 16, "nominal_white_level_luma_code_value" ); + WRITE_CODE( sei.m_extendedWhiteLevelLumaCodeValue, 16, "extended_white_level_luma_code_value" ); + break; + } + default: + { + assert(!"Undefined SEIToneMapModelId"); + break; + } + }//switch m_modelId + }//if(!sei.m_toneMapCancelFlag) +} + +Void SEIWriter::xWriteSEIDisplayOrientation(const SEIDisplayOrientation &sei) +{ + WRITE_FLAG( sei.cancelFlag, "display_orientation_cancel_flag" ); + if( !sei.cancelFlag ) + { + WRITE_FLAG( sei.horFlip, "hor_flip" ); + WRITE_FLAG( sei.verFlip, "ver_flip" ); + WRITE_CODE( sei.anticlockwiseRotation, 16, "anticlockwise_rotation" ); + WRITE_FLAG( sei.persistenceFlag, "display_orientation_persistence_flag" ); + } +} + +Void SEIWriter::xWriteSEITemporalLevel0Index(const SEITemporalLevel0Index &sei) +{ + WRITE_CODE( sei.tl0Idx, 8 , "tl0_idx" ); + WRITE_CODE( sei.rapIdx, 8 , "rap_idx" ); +} + +Void SEIWriter::xWriteSEIGradualDecodingRefreshInfo(const SEIGradualDecodingRefreshInfo &sei) +{ + WRITE_FLAG( sei.m_gdrForegroundFlag, "gdr_foreground_flag"); +} + +Void SEIWriter::xWriteSEINoDisplay(const SEINoDisplay &sei) +{ +} + +Void SEIWriter::xWriteSEISOPDescription(const SEISOPDescription& sei) +{ + WRITE_UVLC( sei.m_sopSeqParameterSetId, "sop_seq_parameter_set_id" ); + WRITE_UVLC( sei.m_numPicsInSopMinus1, "num_pics_in_sop_minus1" ); + for (UInt i = 0; i <= sei.m_numPicsInSopMinus1; i++) + { + WRITE_CODE( sei.m_sopDescVclNaluType[i], 6, "sop_desc_vcl_nalu_type" ); + WRITE_CODE( sei.m_sopDescTemporalId[i], 3, "sop_desc_temporal_id" ); + if (sei.m_sopDescVclNaluType[i] != NAL_UNIT_CODED_SLICE_IDR_W_RADL && sei.m_sopDescVclNaluType[i] != NAL_UNIT_CODED_SLICE_IDR_N_LP) + { + WRITE_UVLC( sei.m_sopDescStRpsIdx[i], "sop_desc_st_rps_idx" ); + } + if (i > 0) + { + WRITE_SVLC( sei.m_sopDescPocDelta[i], "sop_desc_poc_delta" ); + } + } +} + +Void SEIWriter::xWriteSEIScalableNesting(TComBitIf& bs, const SEIScalableNesting& sei, TComSPS *sps) +{ + WRITE_FLAG( sei.m_bitStreamSubsetFlag, "bitstream_subset_flag" ); + WRITE_FLAG( sei.m_nestingOpFlag, "nesting_op_flag " ); + if (sei.m_nestingOpFlag) + { + WRITE_FLAG( sei.m_defaultOpFlag, "default_op_flag" ); + WRITE_UVLC( sei.m_nestingNumOpsMinus1, "nesting_num_ops_minus1" ); + for (UInt i = (sei.m_defaultOpFlag ? 1 : 0); i <= sei.m_nestingNumOpsMinus1; i++) + { + WRITE_CODE( sei.m_nestingMaxTemporalIdPlus1[i], 3, "nesting_max_temporal_id_plus1" ); + WRITE_UVLC( sei.m_nestingOpIdx[i], "nesting_op_idx" ); + } + } + else + { + WRITE_FLAG( sei.m_allLayersFlag, "all_layers_flag" ); + if (!sei.m_allLayersFlag) + { + WRITE_CODE( sei.m_nestingNoOpMaxTemporalIdPlus1, 3, "nesting_no_op_max_temporal_id_plus1" ); + WRITE_UVLC( sei.m_nestingNumLayersMinus1, "nesting_num_layers" ); + for (UInt i = 0; i <= sei.m_nestingNumLayersMinus1; i++) + { + WRITE_CODE( sei.m_nestingLayerId[i], 6, "nesting_layer_id" ); + } + } + } + + // byte alignment + while ( m_pcBitIf->getNumberOfWrittenBits() % 8 != 0 ) + { + WRITE_FLAG( 0, "nesting_zero_bit" ); + } + + // write nested SEI messages + for (SEIMessages::const_iterator it = sei.m_nestedSEIs.begin(); it != sei.m_nestedSEIs.end(); it++) + { + writeSEImessage(bs, *(*it), sps); + } +} + +Void SEIWriter::xWriteSEITempMotionConstrainedTileSets(TComBitIf& bs, const SEITempMotionConstrainedTileSets& sei) +{ + //UInt code; + WRITE_FLAG((sei.m_mc_all_tiles_exact_sample_value_match_flag ? 1 : 0), "mc_all_tiles_exact_sample_value_match_flag"); + WRITE_FLAG((sei.m_each_tile_one_tile_set_flag ? 1 : 0), "each_tile_one_tile_set_flag" ); + + if(!sei.m_each_tile_one_tile_set_flag) + { + WRITE_FLAG((sei.m_limited_tile_set_display_flag ? 1 : 0), "limited_tile_set_display_flag"); + WRITE_UVLC((sei.getNumberOfTileSets() - 1), "num_sets_in_message_minus1" ); + + if(sei.getNumberOfTileSets() > 0) + { + for(Int i = 0; i < sei.getNumberOfTileSets(); i++) + { + WRITE_UVLC(sei.tileSetData(i).m_mcts_id, "mcts_id"); + + if(sei.m_limited_tile_set_display_flag) + { + WRITE_FLAG((sei.tileSetData(i).m_display_tile_set_flag ? 1 : 0), "display_tile_set_flag"); + } + + WRITE_UVLC((sei.tileSetData(i).getNumberOfTileRects() - 1), "num_tile_rects_in_set_minus1"); + + for(Int j = 0; j < sei.tileSetData(i).getNumberOfTileRects(); j++) + { + WRITE_UVLC(sei.tileSetData(i).topLeftTileIndex (j), "top_left_tile_index"); + WRITE_UVLC(sei.tileSetData(i).bottomRightTileIndex(j), "bottom_right_tile_index"); + } + + if(!sei.m_mc_all_tiles_exact_sample_value_match_flag) + { + WRITE_FLAG((sei.tileSetData(i).m_exact_sample_value_match_flag ? 1 : 0), "exact_sample_value_match_flag"); + } + + WRITE_FLAG((sei.tileSetData(i).m_mcts_tier_level_idc_present_flag ? 1 : 0), "mcts_tier_level_idc_present_flag"); + + if(sei.tileSetData(i).m_mcts_tier_level_idc_present_flag) + { + WRITE_FLAG((sei.tileSetData(i).m_mcts_tier_flag ? 1 : 0), "mcts_tier_flag"); + WRITE_CODE( sei.tileSetData(i).m_mcts_level_idc, 8, "mcts_level_idc"); + } + } + } + } + else + { + WRITE_FLAG((sei.m_max_mcs_tier_level_idc_present_flag ? 1 : 0), "max_mcs_tier_level_idc_present_flag"); + + if(sei.m_max_mcs_tier_level_idc_present_flag) + { + WRITE_FLAG((sei.m_max_mcts_tier_flag ? 1 : 0), "max_mcts_tier_flag"); + WRITE_CODE( sei.m_max_mcts_level_idc, 8, "max_mcts_level_idc"); + } + } +} + +Void SEIWriter::xWriteSEITimeCode(const SEITimeCode& sei) +{ + WRITE_CODE(sei.numClockTs, 2, "num_clock_ts"); + for(Int i = 0; i < sei.numClockTs; i++) + { + const TComSEITimeSet ¤tTimeSet = sei.timeSetArray[i]; + WRITE_FLAG(currentTimeSet.clockTimeStampFlag, "clock_time_stamp_flag"); + if(currentTimeSet.clockTimeStampFlag) + { + WRITE_FLAG(currentTimeSet.numUnitFieldBasedFlag, "units_field_based_flag"); + WRITE_CODE(currentTimeSet.countingType, 5, "counting_type"); + WRITE_FLAG(currentTimeSet.fullTimeStampFlag, "full_timestamp_flag"); + WRITE_FLAG(currentTimeSet.discontinuityFlag, "discontinuity_flag"); + WRITE_FLAG(currentTimeSet.cntDroppedFlag, "cnt_dropped_flag"); + WRITE_CODE(currentTimeSet.numberOfFrames, 9, "n_frames"); + if(currentTimeSet.fullTimeStampFlag) + { + WRITE_CODE(currentTimeSet.secondsValue, 6, "seconds_value"); + WRITE_CODE(currentTimeSet.minutesValue, 6, "minutes_value"); + WRITE_CODE(currentTimeSet.hoursValue, 5, "hours_value"); + } + else + { + WRITE_FLAG(currentTimeSet.secondsFlag, "seconds_flag"); + if(currentTimeSet.secondsFlag) + { + WRITE_CODE(currentTimeSet.secondsValue, 6, "seconds_value"); + WRITE_FLAG(currentTimeSet.minutesFlag, "minutes_flag"); + if(currentTimeSet.minutesFlag) + { + WRITE_CODE(currentTimeSet.minutesValue, 6, "minutes_value"); + WRITE_FLAG(currentTimeSet.hoursFlag, "hours_flag"); + if(currentTimeSet.hoursFlag) + WRITE_CODE(currentTimeSet.hoursValue, 5, "hours_value"); + } + } + } + WRITE_CODE(currentTimeSet.timeOffsetLength, 5, "time_offset_length"); + if(currentTimeSet.timeOffsetLength > 0) + { + if(currentTimeSet.timeOffsetValue >= 0) + { + WRITE_CODE((UInt)currentTimeSet.timeOffsetValue, currentTimeSet.timeOffsetLength, "time_offset_value"); + } + else + { + // Two's complement conversion + UInt offsetValue = ~(currentTimeSet.timeOffsetValue) + 1; + offsetValue |= (1 << (currentTimeSet.timeOffsetLength-1)); + WRITE_CODE(offsetValue, currentTimeSet.timeOffsetLength, "time_offset_value"); + } + } + } + } +} + +Void SEIWriter::xWriteSEIChromaSamplingFilterHint(const SEIChromaSamplingFilterHint &sei/*, TComSPS* sps*/) +{ + WRITE_CODE(sei.m_verChromaFilterIdc, 8, "ver_chroma_filter_idc"); + WRITE_CODE(sei.m_horChromaFilterIdc, 8, "hor_chroma_filter_idc"); + WRITE_FLAG(sei.m_verFilteringProcessFlag, "ver_filtering_process_flag"); + if(sei.m_verChromaFilterIdc == 1 || sei.m_horChromaFilterIdc == 1) + { + writeUserDefinedCoefficients(sei); + } +} + +// write hardcoded chroma filter coefficients in the SEI messages +Void SEIWriter::writeUserDefinedCoefficients(const SEIChromaSamplingFilterHint &sei) +{ + Int const iNumVerticalFilters = 3; + Int verticalTapLength_minus1[iNumVerticalFilters] = {5,3,3}; + Int* userVerticalCoefficients[iNumVerticalFilters]; + for(Int i = 0; i < iNumVerticalFilters; i ++) + { + userVerticalCoefficients[i] = (Int*)malloc( (verticalTapLength_minus1[i]+1) * sizeof(Int)); + } + userVerticalCoefficients[0][0] = -3; + userVerticalCoefficients[0][1] = 13; + userVerticalCoefficients[0][2] = 31; + userVerticalCoefficients[0][3] = 23; + userVerticalCoefficients[0][4] = 3; + userVerticalCoefficients[0][5] = -3; + + userVerticalCoefficients[1][0] = -1; + userVerticalCoefficients[1][1] = 25; + userVerticalCoefficients[1][2] = 247; + userVerticalCoefficients[1][3] = -15; + + userVerticalCoefficients[2][0] = -20; + userVerticalCoefficients[2][1] = 186; + userVerticalCoefficients[2][2] = 100; + userVerticalCoefficients[2][3] = -10; + + Int const iNumHorizontalFilters = 1; + Int horizontalTapLength_minus1[iNumHorizontalFilters] = {3}; + Int* userHorizontalCoefficients[iNumHorizontalFilters]; + for(Int i = 0; i < iNumHorizontalFilters; i ++) + { + userHorizontalCoefficients[i] = (Int*)malloc( (horizontalTapLength_minus1[i]+1) * sizeof(Int)); + } + userHorizontalCoefficients[0][0] = 1; + userHorizontalCoefficients[0][1] = 6; + userHorizontalCoefficients[0][2] = 1; + + WRITE_UVLC(3, "target_format_idc"); + if(sei.m_verChromaFilterIdc == 1) + { + WRITE_UVLC(iNumVerticalFilters, "num_vertical_filters"); + if(iNumVerticalFilters > 0) + { + for(Int i = 0; i < iNumVerticalFilters; i ++) + { + WRITE_UVLC(verticalTapLength_minus1[i], "ver_tap_length_minus_1"); + for(Int j = 0; j < verticalTapLength_minus1[i]; j ++) + { + WRITE_SVLC(userVerticalCoefficients[i][j], "ver_filter_coeff"); + } + } + } + } + if(sei.m_horChromaFilterIdc == 1) + { + WRITE_UVLC(iNumHorizontalFilters, "num_horizontal_filters"); + if(iNumHorizontalFilters > 0) + { + for(Int i = 0; i < iNumHorizontalFilters; i ++) + { + WRITE_UVLC(horizontalTapLength_minus1[i], "hor_tap_length_minus_1"); + for(Int j = 0; j < horizontalTapLength_minus1[i]; j ++) + { + WRITE_SVLC(userHorizontalCoefficients[i][j], "hor_filter_coeff"); + } + } + } + } +} + +Void SEIWriter::xWriteSEIKneeFunctionInfo(const SEIKneeFunctionInfo &sei) +{ + WRITE_UVLC( sei.m_kneeId, "knee_function_id" ); + WRITE_FLAG( sei.m_kneeCancelFlag, "knee_function_cancel_flag" ); + if ( !sei.m_kneeCancelFlag ) + { + WRITE_FLAG( sei.m_kneePersistenceFlag, "knee_function_persistence_flag" ); + WRITE_CODE( (UInt)sei.m_kneeInputDrange , 32, "input_d_range" ); + WRITE_CODE( (UInt)sei.m_kneeInputDispLuminance, 32, "input_disp_luminance" ); + WRITE_CODE( (UInt)sei.m_kneeOutputDrange, 32, "output_d_range" ); + WRITE_CODE( (UInt)sei.m_kneeOutputDispLuminance, 32, "output_disp_luminance" ); + WRITE_UVLC( sei.m_kneeNumKneePointsMinus1, "num_knee_points_minus1" ); + for(Int i = 0; i <= sei.m_kneeNumKneePointsMinus1; i++ ) + { + WRITE_CODE( (UInt)sei.m_kneeInputKneePoint[i], 10,"input_knee_point" ); + WRITE_CODE( (UInt)sei.m_kneeOutputKneePoint[i], 10, "output_knee_point" ); + } + } +} + + +Void SEIWriter::xWriteSEIMasteringDisplayColourVolume(const SEIMasteringDisplayColourVolume& sei) +{ + WRITE_CODE( sei.values.primaries[0][0], 16, "display_primaries_x[0]" ); + WRITE_CODE( sei.values.primaries[0][1], 16, "display_primaries_y[0]" ); + + WRITE_CODE( sei.values.primaries[1][0], 16, "display_primaries_x[1]" ); + WRITE_CODE( sei.values.primaries[1][1], 16, "display_primaries_y[1]" ); + + WRITE_CODE( sei.values.primaries[2][0], 16, "display_primaries_x[2]" ); + WRITE_CODE( sei.values.primaries[2][1], 16, "display_primaries_y[2]" ); + + WRITE_CODE( sei.values.whitePoint[0], 16, "white_point_x" ); + WRITE_CODE( sei.values.whitePoint[1], 16, "white_point_y" ); + + WRITE_CODE( sei.values.maxLuminance, 32, "max_display_mastering_luminance" ); + WRITE_CODE( sei.values.minLuminance, 32, "min_display_mastering_luminance" ); +} + + +Void SEIWriter::xWriteByteAlign() +{ + if( m_pcBitIf->getNumberOfWrittenBits() % 8 != 0) + { + WRITE_FLAG( 1, "payload_bit_equal_to_one" ); + while( m_pcBitIf->getNumberOfWrittenBits() % 8 != 0 ) + { + WRITE_FLAG( 0, "payload_bit_equal_to_zero" ); + } + } +} + +//! \} diff --git a/jctvc/TLibEncoder/SEIwrite.h b/jctvc/TLibEncoder/SEIwrite.h new file mode 100644 index 0000000..81416ba --- /dev/null +++ b/jctvc/TLibEncoder/SEIwrite.h @@ -0,0 +1,84 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#ifndef __SEIWRITE__ +#define __SEIWRITE__ + +#include "SyntaxElementWriter.h" +#include "TLibCommon/SEI.h" + +class TComBitIf; + +//! \ingroup TLibEncoder +//! \{ +class SEIWriter:public SyntaxElementWriter +{ +public: + SEIWriter() {}; + virtual ~SEIWriter() {}; + + Void writeSEImessage(TComBitIf& bs, const SEI& sei, TComSPS *sps); + +protected: + Void xWriteSEIpayloadData(TComBitIf& bs, const SEI& sei, TComSPS *sps); + Void xWriteSEIuserDataUnregistered(const SEIuserDataUnregistered &sei); + Void xWriteSEIActiveParameterSets(const SEIActiveParameterSets& sei); + Void xWriteSEIDecodingUnitInfo(const SEIDecodingUnitInfo& sei, TComSPS *sps); + Void xWriteSEIDecodedPictureHash(const SEIDecodedPictureHash& sei); + Void xWriteSEIBufferingPeriod(const SEIBufferingPeriod& sei, TComSPS *sps); + Void xWriteSEIPictureTiming(const SEIPictureTiming& sei, TComSPS *sps); + TComSPS *m_pSPS; + Void xWriteSEIRecoveryPoint(const SEIRecoveryPoint& sei); + Void xWriteSEIFramePacking(const SEIFramePacking& sei); + Void xWriteSEISegmentedRectFramePacking(const SEISegmentedRectFramePacking& sei); + Void xWriteSEIDisplayOrientation(const SEIDisplayOrientation &sei); + Void xWriteSEITemporalLevel0Index(const SEITemporalLevel0Index &sei); + Void xWriteSEIGradualDecodingRefreshInfo(const SEIGradualDecodingRefreshInfo &sei); + Void xWriteSEINoDisplay(const SEINoDisplay &sei); + Void xWriteSEIToneMappingInfo(const SEIToneMappingInfo& sei); + Void xWriteSEISOPDescription(const SEISOPDescription& sei); + Void xWriteSEIScalableNesting(TComBitIf& bs, const SEIScalableNesting& sei, TComSPS *sps); + Void xWriteSEITempMotionConstrainedTileSets(TComBitIf& bs, const SEITempMotionConstrainedTileSets& sei); + Void xWriteSEITimeCode(const SEITimeCode& sei); + Void xWriteSEIChromaSamplingFilterHint(const SEIChromaSamplingFilterHint& sei/*, TComSPS *sps*/); + Void writeUserDefinedCoefficients(const SEIChromaSamplingFilterHint& sei); + Void xWriteSEIKneeFunctionInfo(const SEIKneeFunctionInfo &sei); + Void xWriteSEIMasteringDisplayColourVolume( const SEIMasteringDisplayColourVolume& sei); + Void xWriteByteAlign(); +}; + +//! \} + +#endif diff --git a/jctvc/TLibEncoder/SyntaxElementWriter.cpp b/jctvc/TLibEncoder/SyntaxElementWriter.cpp new file mode 100644 index 0000000..91f1b78 --- /dev/null +++ b/jctvc/TLibEncoder/SyntaxElementWriter.cpp @@ -0,0 +1,132 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file SyntaxElementWriter.cpp + \brief CAVLC encoder class +*/ + +#include "TLibCommon/CommonDef.h" +#include "SyntaxElementWriter.h" + +//! \ingroup TLibEncoder +//! \{ + +#if ENC_DEC_TRACE + +Void SyntaxElementWriter::xWriteCodeTr (UInt value, UInt length, const Char *pSymbolName) +{ + xWriteCode (value,length); + if( g_HLSTraceEnable ) + { + fprintf( g_hTrace, "%8lld ", g_nSymbolCounter++ ); + if( length<10 ) + { + fprintf( g_hTrace, "%-50s u(%d) : %d\n", pSymbolName, length, value ); + } + else + { + fprintf( g_hTrace, "%-50s u(%d) : %d\n", pSymbolName, length, value ); + } + } +} + +Void SyntaxElementWriter::xWriteUvlcTr (UInt value, const Char *pSymbolName) +{ + xWriteUvlc (value); + if( g_HLSTraceEnable ) + { + fprintf( g_hTrace, "%8lld ", g_nSymbolCounter++ ); + fprintf( g_hTrace, "%-50s ue(v) : %d\n", pSymbolName, value ); + } +} + +Void SyntaxElementWriter::xWriteSvlcTr (Int value, const Char *pSymbolName) +{ + xWriteSvlc(value); + if( g_HLSTraceEnable ) + { + fprintf( g_hTrace, "%8lld ", g_nSymbolCounter++ ); + fprintf( g_hTrace, "%-50s se(v) : %d\n", pSymbolName, value ); + } +} + +Void SyntaxElementWriter::xWriteFlagTr(UInt value, const Char *pSymbolName) +{ + xWriteFlag(value); + if( g_HLSTraceEnable ) + { + fprintf( g_hTrace, "%8lld ", g_nSymbolCounter++ ); + fprintf( g_hTrace, "%-50s u(1) : %d\n", pSymbolName, value ); + } +} + +#endif + + +Void SyntaxElementWriter::xWriteCode ( UInt uiCode, UInt uiLength ) +{ + assert ( uiLength > 0 ); + m_pcBitIf->write( uiCode, uiLength ); +} + +Void SyntaxElementWriter::xWriteUvlc ( UInt uiCode ) +{ + UInt uiLength = 1; + UInt uiTemp = ++uiCode; + + assert ( uiTemp ); + + while( 1 != uiTemp ) + { + uiTemp >>= 1; + uiLength += 2; + } + // Take care of cases where uiLength > 32 + m_pcBitIf->write( 0, uiLength >> 1); + m_pcBitIf->write( uiCode, (uiLength+1) >> 1); +} + +Void SyntaxElementWriter::xWriteSvlc ( Int iCode ) +{ + UInt uiCode; + + uiCode = xConvertToUInt( iCode ); + xWriteUvlc( uiCode ); +} + +Void SyntaxElementWriter::xWriteFlag( UInt uiCode ) +{ + m_pcBitIf->write( uiCode, 1 ); +} + +//! \} diff --git a/jctvc/TLibEncoder/SyntaxElementWriter.h b/jctvc/TLibEncoder/SyntaxElementWriter.h new file mode 100644 index 0000000..3d84ecf --- /dev/null +++ b/jctvc/TLibEncoder/SyntaxElementWriter.h @@ -0,0 +1,97 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file SyntaxElementWriter.h + \brief CAVLC encoder class (header) +*/ + +#ifndef __SYNTAXELEMENTWRITER__ +#define __SYNTAXELEMENTWRITER__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/TComRom.h" + +//! \ingroup TLibEncoder +//! \{ + +#if ENC_DEC_TRACE + +#define WRITE_CODE( value, length, name) xWriteCodeTr ( value, length, name ) +#define WRITE_UVLC( value, name) xWriteUvlcTr ( value, name ) +#define WRITE_SVLC( value, name) xWriteSvlcTr ( value, name ) +#define WRITE_FLAG( value, name) xWriteFlagTr ( value, name ) + +#else + +#define WRITE_CODE( value, length, name) xWriteCode ( value, length ) +#define WRITE_UVLC( value, name) xWriteUvlc ( value ) +#define WRITE_SVLC( value, name) xWriteSvlc ( value ) +#define WRITE_FLAG( value, name) xWriteFlag ( value ) + +#endif + +class SyntaxElementWriter +{ +protected: + TComBitIf* m_pcBitIf; + + SyntaxElementWriter() + :m_pcBitIf(NULL) + {}; + virtual ~SyntaxElementWriter() {}; + + Void setBitstream ( TComBitIf* p ) { m_pcBitIf = p; } + + Void xWriteCode ( UInt uiCode, UInt uiLength ); + Void xWriteUvlc ( UInt uiCode ); + Void xWriteSvlc ( Int iCode ); + Void xWriteFlag ( UInt uiCode ); +#if ENC_DEC_TRACE + Void xWriteCodeTr ( UInt value, UInt length, const Char *pSymbolName); + Void xWriteUvlcTr ( UInt value, const Char *pSymbolName); + Void xWriteSvlcTr ( Int value, const Char *pSymbolName); + Void xWriteFlagTr ( UInt value, const Char *pSymbolName); +#endif + + UInt xConvertToUInt ( Int iValue ) { return ( iValue <= 0) ? -iValue<<1 : (iValue<<1)-1; } +}; + +//! \} + +#endif // !defined(__SYNTAXELEMENTWRITER__) + diff --git a/jctvc/TLibEncoder/TEncAnalyze.cpp b/jctvc/TLibEncoder/TEncAnalyze.cpp new file mode 100644 index 0000000..198c500 --- /dev/null +++ b/jctvc/TLibEncoder/TEncAnalyze.cpp @@ -0,0 +1,54 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncAnalyze.cpp + \brief encoder analyzer class +*/ + +#include "TEncAnalyze.h" + +//! \ingroup TLibEncoder +//! \{ + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +TEncAnalyze m_gcAnalyzeAll; +TEncAnalyze m_gcAnalyzeI; +TEncAnalyze m_gcAnalyzeP; +TEncAnalyze m_gcAnalyzeB; + +TEncAnalyze m_gcAnalyzeAll_in; + +//! \} diff --git a/jctvc/TLibEncoder/TEncAnalyze.h b/jctvc/TLibEncoder/TEncAnalyze.h new file mode 100644 index 0000000..01c8e1b --- /dev/null +++ b/jctvc/TLibEncoder/TEncAnalyze.h @@ -0,0 +1,366 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncAnalyze.h + \brief encoder analyzer class (header) +*/ + +#ifndef __TENCANALYZE__ +#define __TENCANALYZE__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include +#include +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComChromaFormat.h" +#include "math.h" + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// encoder analyzer class +class TEncAnalyze +{ +private: + Double m_dPSNRSum[MAX_NUM_COMPONENT]; + Double m_dAddBits; + UInt m_uiNumPic; + Double m_dFrmRate; //--CFG_KDY + Double m_MSEyuvframe[MAX_NUM_COMPONENT]; // sum of MSEs + +public: + virtual ~TEncAnalyze() {} + TEncAnalyze() { clear(); } + + Void addResult( Double psnr[MAX_NUM_COMPONENT], Double bits, const Double MSEyuvframe[MAX_NUM_COMPONENT]) + { + m_dAddBits += bits; + for(UInt i=0; i maximumBitDepth) + maximumBitDepth = g_bitDepth[channelTypeIndex]; + + const UInt maxval = 255 << (maximumBitDepth - 8); + const UInt numberValidComponents = getNumberValidComponents(chFmt); + + for (UInt comp=0; comp>(csx+csy)); + const UInt bitDepthShift = 2 * (maximumBitDepth - g_bitDepth[toChannelType(compID)]); //*2 because this is a squared number + + const Double channelMSE = (m_MSEyuvframe[compID] * Double(1 << bitDepthShift)) / Double(getNumPic()); + + scale += scaleChan; + MSEyuv += scaleChan * channelMSE; + } + + MSEyuv /= Double(scale); // i.e. divide by 6 for 4:2:0, 8 for 4:2:2 etc. + PSNRyuv = (MSEyuv==0 ? 999.99 : 10*log10((maxval*maxval)/MSEyuv)); + } + + + Void printOut ( Char cDelim, const ChromaFormat chFmt, const Bool printMSEBasedSNR, const Bool printSequenceMSE ) + { + Double dFps = m_dFrmRate; //--CFG_KDY + Double dScale = dFps / 1000 / (Double)m_uiNumPic; + + Double MSEBasedSNR[MAX_NUM_COMPONENT]; + if (printMSEBasedSNR) + { + for (UInt componentIndex = 0; componentIndex < MAX_NUM_COMPONENT; componentIndex++) + { + const ComponentID compID = ComponentID(componentIndex); + + if (getNumPic() == 0) MSEBasedSNR[compID] = 0 * dScale; // this is the same calculation that will be evaluated for any other statistic when there are no frames (it should result in NaN). We use it here so all the output is consistent. + else + { + //NOTE: this is not the true maximum value for any bitDepth other than 8. It comes from the original HM PSNR calculation + const UInt maxval = 255 << (g_bitDepth[toChannelType(compID)] - 8); + const Double MSE = m_MSEyuvframe[compID]; + + MSEBasedSNR[compID] = (MSE == 0) ? 999.99 : (10 * log10((maxval * maxval) / (MSE / (Double)getNumPic()))); + } + } + } + + switch (chFmt) + { + case CHROMA_400: + if (printMSEBasedSNR) + { + printf( " \tTotal Frames | " "Bitrate " "Y-PSNR" ); + + if (printSequenceMSE) printf( " Y-MSE\n" ); + else printf("\n"); + + //printf( "\t------------ " " ----------" " -------- " " -------- " " --------\n" ); + printf( "Average: \t %8d %c " "%12.4lf " "%8.4lf", + getNumPic(), cDelim, + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic() ); + + if (printSequenceMSE) + { + printf( " %8.4lf\n", m_MSEyuvframe[COMPONENT_Y ] / (Double)getNumPic() ); + } + else printf("\n"); + + printf( "From MSE:\t %8d %c " "%12.4lf " "%8.4lf\n", + getNumPic(), cDelim, + getBits() * dScale, + MSEBasedSNR[COMPONENT_Y] ); + } + else + { + printf( "\tTotal Frames | " "Bitrate " "Y-PSNR" ); + + if (printSequenceMSE) printf( " Y-MSE\n" ); + else printf("\n"); + + //printf( "\t------------ " " ----------" " -------- " " -------- " " --------\n" ); + printf( "\t %8d %c " "%12.4lf " "%8.4lf", + getNumPic(), cDelim, + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic() ); + + if (printSequenceMSE) + { + printf( " %8.4lf\n", m_MSEyuvframe[COMPONENT_Y ] / (Double)getNumPic() ); + } + else printf("\n"); + } + break; + case CHROMA_420: + case CHROMA_422: + case CHROMA_444: + { + Double PSNRyuv = MAX_DOUBLE; + Double MSEyuv = MAX_DOUBLE; + + calculateCombinedValues(chFmt, PSNRyuv, MSEyuv); + + if (printMSEBasedSNR) + { + printf( " \tTotal Frames | " "Bitrate " "Y-PSNR " "U-PSNR " "V-PSNR " "YUV-PSNR " ); + + if (printSequenceMSE) printf( " Y-MSE " "U-MSE " "V-MSE " "YUV-MSE \n" ); + else printf("\n"); + + //printf( "\t------------ " " ----------" " -------- " " -------- " " --------\n" ); + printf( "Average: \t %8d %c " "%12.4lf " "%8.4lf " "%8.4lf " "%8.4lf " "%8.4lf", + getNumPic(), cDelim, + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic(), + getPsnr(COMPONENT_Cb) / (Double)getNumPic(), + getPsnr(COMPONENT_Cr) / (Double)getNumPic(), + PSNRyuv ); + + if (printSequenceMSE) + { + printf( " %8.4lf " "%8.4lf " "%8.4lf " "%8.4lf\n", + m_MSEyuvframe[COMPONENT_Y ] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cb] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cr] / (Double)getNumPic(), + MSEyuv ); + } + else printf("\n"); + + printf( "From MSE:\t %8d %c " "%12.4lf " "%8.4lf " "%8.4lf " "%8.4lf " "%8.4lf\n", + getNumPic(), cDelim, + getBits() * dScale, + MSEBasedSNR[COMPONENT_Y], + MSEBasedSNR[COMPONENT_Cb], + MSEBasedSNR[COMPONENT_Cr], + PSNRyuv ); + } + else + { + printf( "\tTotal Frames | " "Bitrate " "Y-PSNR " "U-PSNR " "V-PSNR " "YUV-PSNR " ); + + if (printSequenceMSE) printf( " Y-MSE " "U-MSE " "V-MSE " "YUV-MSE \n" ); + else printf("\n"); + + //printf( "\t------------ " " ----------" " -------- " " -------- " " --------\n" ); + printf( "\t %8d %c " "%12.4lf " "%8.4lf " "%8.4lf " "%8.4lf " "%8.4lf", + getNumPic(), cDelim, + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic(), + getPsnr(COMPONENT_Cb) / (Double)getNumPic(), + getPsnr(COMPONENT_Cr) / (Double)getNumPic(), + PSNRyuv ); + + if (printSequenceMSE) + { + printf( " %8.4lf " "%8.4lf " "%8.4lf " "%8.4lf\n", + m_MSEyuvframe[COMPONENT_Y ] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cb] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cr] / (Double)getNumPic(), + MSEyuv ); + } + else printf("\n"); + } + } + break; + default: + fprintf(stderr, "Unknown format during print out\n"); + exit(1); + break; + } + } + + + Void printSummary(const ChromaFormat chFmt, const Bool printSequenceMSE, Char ch='T') + { + FILE* pFile = NULL; + + switch( ch ) + { + case 'T': + pFile = fopen ("summaryTotal.txt", "at"); + break; + case 'I': + pFile = fopen ("summary_I.txt", "at"); + break; + case 'P': + pFile = fopen ("summary_P.txt", "at"); + break; + case 'B': + pFile = fopen ("summary_B.txt", "at"); + break; + default: + assert(0); + return; + break; + } + + Double dFps = m_dFrmRate; //--CFG_KDY + Double dScale = dFps / 1000 / (Double)m_uiNumPic; + switch (chFmt) + { + case CHROMA_400: + fprintf(pFile, "%f\t %f\n", + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic() ); + break; + case CHROMA_420: + case CHROMA_422: + case CHROMA_444: + { + Double PSNRyuv = MAX_DOUBLE; + Double MSEyuv = MAX_DOUBLE; + + calculateCombinedValues(chFmt, PSNRyuv, MSEyuv); + + fprintf(pFile, "%f\t %f\t %f\t %f\t %f", + getBits() * dScale, + getPsnr(COMPONENT_Y) / (Double)getNumPic(), + getPsnr(COMPONENT_Cb) / (Double)getNumPic(), + getPsnr(COMPONENT_Cr) / (Double)getNumPic(), + PSNRyuv ); + + if (printSequenceMSE) + { + fprintf(pFile, "\t %f\t %f\t %f\t %f\n", + m_MSEyuvframe[COMPONENT_Y ] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cb] / (Double)getNumPic(), + m_MSEyuvframe[COMPONENT_Cr] / (Double)getNumPic(), + MSEyuv ); + } + else fprintf(pFile, "\n"); + + break; + } + + default: + fprintf(stderr, "Unknown format during print out\n"); + exit(1); + break; + } + + fclose(pFile); + } +}; + +extern TEncAnalyze m_gcAnalyzeAll; +extern TEncAnalyze m_gcAnalyzeI; +extern TEncAnalyze m_gcAnalyzeP; +extern TEncAnalyze m_gcAnalyzeB; + +extern TEncAnalyze m_gcAnalyzeAll_in; + +//! \} + +#endif // !defined(AFX_TENCANALYZE_H__C79BCAA2_6AC8_4175_A0FE_CF02F5829233__INCLUDED_) diff --git a/jctvc/TLibEncoder/TEncBinCoder.h b/jctvc/TLibEncoder/TEncBinCoder.h new file mode 100644 index 0000000..5935091 --- /dev/null +++ b/jctvc/TLibEncoder/TEncBinCoder.h @@ -0,0 +1,83 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncBinCoder.h + \brief binary entropy encoder interface +*/ + +#ifndef __TENCBINCODER__ +#define __TENCBINCODER__ + +#include "TLibCommon/ContextModel.h" +#include "TLibCommon/TComBitStream.h" + +//! \ingroup TLibEncoder +//! \{ + +class TEncBinCABAC; + +class TEncBinIf +{ +public: + virtual Void init ( TComBitIf* pcTComBitIf ) = 0; + virtual Void uninit () = 0; + + virtual Void start () = 0; + virtual Void finish () = 0; + virtual Void copyState ( const TEncBinIf* pcTEncBinIf ) = 0; + virtual Void flush () = 0; + + virtual Void resetBac () = 0; + virtual Void encodePCMAlignBits() = 0; + virtual Void xWritePCMCode ( UInt uiCode, UInt uiLength ) = 0; + + virtual Void resetBits () = 0; + virtual UInt getNumWrittenBits () = 0; + + virtual Void encodeBin ( UInt uiBin, ContextModel& rcCtxModel ) = 0; + virtual Void encodeBinEP ( UInt uiBin ) = 0; + virtual Void encodeBinsEP ( UInt uiBins, Int numBins ) = 0; + virtual Void encodeBinTrm ( UInt uiBin ) = 0; + + virtual Void align () = 0; + + virtual TEncBinCABAC* getTEncBinCABAC () { return 0; } + virtual const TEncBinCABAC* getTEncBinCABAC () const { return 0; } + + virtual ~TEncBinIf() {} +}; + +//! \} + +#endif + diff --git a/jctvc/TLibEncoder/TEncBinCoderCABAC.cpp b/jctvc/TLibEncoder/TEncBinCoderCABAC.cpp new file mode 100644 index 0000000..7cadb1f --- /dev/null +++ b/jctvc/TLibEncoder/TEncBinCoderCABAC.cpp @@ -0,0 +1,440 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncBinCoderCABAC.cpp + \brief binary entropy encoder of CABAC +*/ + +#include "TEncBinCoderCABAC.h" +#include "TLibCommon/TComRom.h" +#include "TLibCommon/Debug.h" + +//! \ingroup TLibEncoder +//! \{ + + +TEncBinCABAC::TEncBinCABAC() +: m_pcTComBitIf( 0 ) +, m_binCountIncrement( 0 ) +#if FAST_BIT_EST +, m_fracBits( 0 ) +#endif +{ +} + +TEncBinCABAC::~TEncBinCABAC() +{ +} + +Void TEncBinCABAC::init( TComBitIf* pcTComBitIf ) +{ + m_pcTComBitIf = pcTComBitIf; +} + +Void TEncBinCABAC::uninit() +{ + m_pcTComBitIf = 0; +} + +Void TEncBinCABAC::start() +{ + m_uiLow = 0; + m_uiRange = 510; + m_bitsLeft = 23; + m_numBufferedBytes = 0; + m_bufferedByte = 0xff; +#if FAST_BIT_EST + m_fracBits = 0; +#endif +} + +Void TEncBinCABAC::finish() +{ + if ( m_uiLow >> ( 32 - m_bitsLeft ) ) + { + //assert( m_numBufferedBytes > 0 ); + //assert( m_bufferedByte != 0xff ); + m_pcTComBitIf->write( m_bufferedByte + 1, 8 ); + while ( m_numBufferedBytes > 1 ) + { + m_pcTComBitIf->write( 0x00, 8 ); + m_numBufferedBytes--; + } + m_uiLow -= 1 << ( 32 - m_bitsLeft ); + } + else + { + if ( m_numBufferedBytes > 0 ) + { + m_pcTComBitIf->write( m_bufferedByte, 8 ); + } + while ( m_numBufferedBytes > 1 ) + { + m_pcTComBitIf->write( 0xff, 8 ); + m_numBufferedBytes--; + } + } + m_pcTComBitIf->write( m_uiLow >> 8, 24 - m_bitsLeft ); +} + +Void TEncBinCABAC::flush() +{ + encodeBinTrm(1); + finish(); + m_pcTComBitIf->write(1, 1); + m_pcTComBitIf->writeAlignZero(); + + start(); +} + +/** Reset BAC register and counter values. + * \returns Void + */ +Void TEncBinCABAC::resetBac() +{ + start(); +} + +/** Encode PCM alignment zero bits. + * \returns Void + */ +Void TEncBinCABAC::encodePCMAlignBits() +{ + finish(); + m_pcTComBitIf->write(1, 1); + m_pcTComBitIf->writeAlignZero(); // pcm align zero +} + +/** Write a PCM code. + * \param uiCode code value + * \param uiLength code bit-depth + * \returns Void + */ +Void TEncBinCABAC::xWritePCMCode(UInt uiCode, UInt uiLength) +{ + m_pcTComBitIf->write(uiCode, uiLength); +} + +Void TEncBinCABAC::copyState( const TEncBinIf* pcTEncBinIf ) +{ + const TEncBinCABAC* pcTEncBinCABAC = pcTEncBinIf->getTEncBinCABAC(); + m_uiLow = pcTEncBinCABAC->m_uiLow; + m_uiRange = pcTEncBinCABAC->m_uiRange; + m_bitsLeft = pcTEncBinCABAC->m_bitsLeft; + m_bufferedByte = pcTEncBinCABAC->m_bufferedByte; + m_numBufferedBytes = pcTEncBinCABAC->m_numBufferedBytes; +#if FAST_BIT_EST + m_fracBits = pcTEncBinCABAC->m_fracBits; +#endif +} + +Void TEncBinCABAC::resetBits() +{ + m_uiLow = 0; + m_bitsLeft = 23; + m_numBufferedBytes = 0; + m_bufferedByte = 0xff; + if ( m_binCountIncrement ) + { + m_uiBinsCoded = 0; + } +#if FAST_BIT_EST + m_fracBits &= 32767; +#endif +} + +UInt TEncBinCABAC::getNumWrittenBits() +{ + return m_pcTComBitIf->getNumberOfWrittenBits() + 8 * m_numBufferedBytes + 23 - m_bitsLeft; +} + +/** + * \brief Encode bin + * + * \param binValue bin value + * \param rcCtxModel context model + */ +Void TEncBinCABAC::encodeBin( UInt binValue, ContextModel &rcCtxModel ) +{ + //{ + // DTRACE_CABAC_VL( g_nSymbolCounter++ ) + // DTRACE_CABAC_T( "\tstate=" ) + // DTRACE_CABAC_V( ( rcCtxModel.getState() << 1 ) + rcCtxModel.getMps() ) + // DTRACE_CABAC_T( "\tsymbol=" ) + // DTRACE_CABAC_V( binValue ) + // DTRACE_CABAC_T( "\n" ) + //} + +#ifdef DEBUG_CABAC_BINS + const UInt startingRange = m_uiRange; +#endif + + m_uiBinsCoded += m_binCountIncrement; + rcCtxModel.setBinsCoded( 1 ); + + UInt uiLPS = TComCABACTables::sm_aucLPSTable[ rcCtxModel.getState() ][ ( m_uiRange >> 6 ) & 3 ]; + m_uiRange -= uiLPS; + + if( binValue != rcCtxModel.getMps() ) + { + Int numBits = TComCABACTables::sm_aucRenormTable[ uiLPS >> 3 ]; + m_uiLow = ( m_uiLow + m_uiRange ) << numBits; + m_uiRange = uiLPS << numBits; + rcCtxModel.updateLPS(); + m_bitsLeft -= numBits; + testAndWriteOut(); + } + else + { + rcCtxModel.updateMPS(); + + if ( m_uiRange < 256 ) + { + m_uiLow <<= 1; + m_uiRange <<= 1; + m_bitsLeft--; + testAndWriteOut(); + } + } + +#ifdef DEBUG_CABAC_BINS + if ((g_debugCounter + debugCabacBinWindow) >= debugCabacBinTargetLine) + std::cout << g_debugCounter << ": coding bin value " << binValue << ", range = [" << startingRange << "->" << m_uiRange << "]\n"; + + if (g_debugCounter >= debugCabacBinTargetLine) + { + Char breakPointThis; + breakPointThis = 7; + } + if (g_debugCounter >= (debugCabacBinTargetLine + debugCabacBinWindow)) exit(0); + g_debugCounter++; +#endif +} + +/** + * \brief Encode equiprobable bin + * + * \param binValue bin value + */ +Void TEncBinCABAC::encodeBinEP( UInt binValue ) +{ + if (false) + { + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tEPsymbol=" ) + DTRACE_CABAC_V( binValue ) + DTRACE_CABAC_T( "\n" ) + } + + m_uiBinsCoded += m_binCountIncrement; + + if (m_uiRange == 256) + { + encodeAlignedBinsEP(binValue, 1); + return; + } + + m_uiLow <<= 1; + if( binValue ) + { + m_uiLow += m_uiRange; + } + m_bitsLeft--; + + testAndWriteOut(); +} + +/** + * \brief Encode equiprobable bins + * + * \param binValues bin values + * \param numBins number of bins + */ +Void TEncBinCABAC::encodeBinsEP( UInt binValues, Int numBins ) +{ + m_uiBinsCoded += numBins & -m_binCountIncrement; + + if (false) + { + for ( Int i = 0; i < numBins; i++ ) + { + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tEPsymbol=" ) + DTRACE_CABAC_V( ( binValues >> ( numBins - 1 - i ) ) & 1 ) + DTRACE_CABAC_T( "\n" ) + } + } + + if (m_uiRange == 256) + { + encodeAlignedBinsEP(binValues, numBins); + return; + } + + while ( numBins > 8 ) + { + numBins -= 8; + UInt pattern = binValues >> numBins; + m_uiLow <<= 8; + m_uiLow += m_uiRange * pattern; + binValues -= pattern << numBins; + m_bitsLeft -= 8; + + testAndWriteOut(); + } + + m_uiLow <<= numBins; + m_uiLow += m_uiRange * binValues; + m_bitsLeft -= numBins; + + testAndWriteOut(); +} + +Void TEncBinCABAC::align() +{ + m_uiRange = 256; +} + +Void TEncBinCABAC::encodeAlignedBinsEP( UInt binValues, Int numBins ) +{ + Int binsRemaining = numBins; + + assert(m_uiRange == 256); //aligned encode only works when range = 256 + + while (binsRemaining > 0) + { + const UInt binsToCode = std::min(binsRemaining, 8); //code bytes if able to take advantage of the system's byte-write function + const UInt binMask = (1 << binsToCode) - 1; + + const UInt newBins = (binValues >> (binsRemaining - binsToCode)) & binMask; + + //The process of encoding an EP bin is the same as that of coding a normal + //bin where the symbol ranges for 1 and 0 are both half the range: + // + // low = (low + range/2) << 1 (to encode a 1) + // low = low << 1 (to encode a 0) + // + // i.e. + // low = (low + (bin * range/2)) << 1 + // + // which is equivalent to: + // + // low = (low << 1) + (bin * range) + // + // this can be generalised for multiple bins, producing the following expression: + // + m_uiLow = (m_uiLow << binsToCode) + (newBins << 8); //range is known to be 256 + + binsRemaining -= binsToCode; + m_bitsLeft -= binsToCode; + + testAndWriteOut(); + } +} + +/** + * \brief Encode terminating bin + * + * \param binValue bin value + */ +Void TEncBinCABAC::encodeBinTrm( UInt binValue ) +{ + m_uiBinsCoded += m_binCountIncrement; + m_uiRange -= 2; + if( binValue ) + { + m_uiLow += m_uiRange; + m_uiLow <<= 7; + m_uiRange = 2 << 7; + m_bitsLeft -= 7; + } + else if ( m_uiRange >= 256 ) + { + return; + } + else + { + m_uiLow <<= 1; + m_uiRange <<= 1; + m_bitsLeft--; + } + + testAndWriteOut(); +} + +Void TEncBinCABAC::testAndWriteOut() +{ + if ( m_bitsLeft < 12 ) + { + writeOut(); + } +} + +/** + * \brief Move bits from register into bitstream + */ +Void TEncBinCABAC::writeOut() +{ + UInt leadByte = m_uiLow >> (24 - m_bitsLeft); + m_bitsLeft += 8; + m_uiLow &= 0xffffffffu >> m_bitsLeft; + + if ( leadByte == 0xff ) + { + m_numBufferedBytes++; + } + else + { + if ( m_numBufferedBytes > 0 ) + { + UInt carry = leadByte >> 8; + UInt byte = m_bufferedByte + carry; + m_bufferedByte = leadByte & 0xff; + m_pcTComBitIf->write( byte, 8 ); + + byte = ( 0xff + carry ) & 0xff; + while ( m_numBufferedBytes > 1 ) + { + m_pcTComBitIf->write( byte, 8 ); + m_numBufferedBytes--; + } + } + else + { + m_numBufferedBytes = 1; + m_bufferedByte = leadByte; + } + } +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncBinCoderCABAC.h b/jctvc/TLibEncoder/TEncBinCoderCABAC.h new file mode 100644 index 0000000..87cbfc0 --- /dev/null +++ b/jctvc/TLibEncoder/TEncBinCoderCABAC.h @@ -0,0 +1,108 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncBinCoderCABAC.h + \brief binary entropy encoder of CABAC +*/ + +#ifndef __TENCBINCODERCABAC__ +#define __TENCBINCODERCABAC__ + +#include "TLibCommon/TComCABACTables.h" +#include "TEncBinCoder.h" + +//! \ingroup TLibEncoder +//! \{ + +class TEncBinCABAC : public TEncBinIf +{ +public: + TEncBinCABAC (); + virtual ~TEncBinCABAC(); + + Void init ( TComBitIf* pcTComBitIf ); + Void uninit (); + + Void start (); + Void finish (); + Void copyState ( const TEncBinIf* pcTEncBinIf ); + Void flush (); + + Void resetBac (); + Void encodePCMAlignBits(); + Void xWritePCMCode ( UInt uiCode, UInt uiLength ); + + Void resetBits (); + UInt getNumWrittenBits (); + + Void encodeBin ( UInt binValue, ContextModel& rcCtxModel ); + Void encodeBinEP ( UInt binValue ); + Void encodeBinsEP ( UInt binValues, Int numBins ); + Void encodeBinTrm ( UInt binValue ); + + Void align (); + Void encodeAlignedBinsEP( UInt binValues, Int numBins ); + + TEncBinCABAC* getTEncBinCABAC() { return this; } + const TEncBinCABAC* getTEncBinCABAC() const { return this; } + + Void setBinsCoded ( UInt uiVal ) { m_uiBinsCoded = uiVal; } + UInt getBinsCoded () { return m_uiBinsCoded; } + Void setBinCountingEnableFlag ( Bool bFlag ) { m_binCountIncrement = bFlag ? 1 : 0; } + Bool getBinCountingEnableFlag () { return m_binCountIncrement != 0; } + +#if FAST_BIT_EST +protected: +#else +private: +#endif + Void testAndWriteOut(); + Void writeOut(); + + TComBitIf* m_pcTComBitIf; + UInt m_uiLow; + UInt m_uiRange; + UInt m_bufferedByte; + Int m_numBufferedBytes; + Int m_bitsLeft; + UInt m_uiBinsCoded; + Int m_binCountIncrement; +#if FAST_BIT_EST + UInt64 m_fracBits; +#endif +}; + +//! \} + +#endif + diff --git a/jctvc/TLibEncoder/TEncBinCoderCABACCounter.cpp b/jctvc/TLibEncoder/TEncBinCoderCABACCounter.cpp new file mode 100644 index 0000000..8bcb3f7 --- /dev/null +++ b/jctvc/TLibEncoder/TEncBinCoderCABACCounter.cpp @@ -0,0 +1,139 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncBinCoderCABAC.cpp + \brief binary entropy encoder of CABAC +*/ + +#include "TEncBinCoderCABACCounter.h" +#include "TLibCommon/TComRom.h" +#include "TLibCommon/Debug.h" + + +#if FAST_BIT_EST + +//! \ingroup TLibEncoder +//! \{ + + +TEncBinCABACCounter::TEncBinCABACCounter() +{ +} + +TEncBinCABACCounter::~TEncBinCABACCounter() +{ +} + +Void TEncBinCABACCounter::finish() +{ + m_pcTComBitIf->write(0, UInt(m_fracBits >> 15) ); + m_fracBits &= 32767; +} + +UInt TEncBinCABACCounter::getNumWrittenBits() +{ + return m_pcTComBitIf->getNumberOfWrittenBits() + UInt( m_fracBits >> 15 ); +} + +/** + * \brief Encode bin + * + * \param binValue bin value + * \param rcCtxModel context model + */ +Void TEncBinCABACCounter::encodeBin( UInt binValue, ContextModel &rcCtxModel ) +{ +#ifdef DEBUG_ENCODER_SEARCH_BINS + const UInt64 startingFracBits = m_fracBits; +#endif + + m_uiBinsCoded += m_binCountIncrement; + m_fracBits += rcCtxModel.getEntropyBits( binValue ); + rcCtxModel.update( binValue ); + +#ifdef DEBUG_ENCODER_SEARCH_BINS + if ((g_debugCounter + debugEncoderSearchBinWindow) >= debugEncoderSearchBinTargetLine) + std::cout << g_debugCounter << ": coding bin value " << binValue << ", fracBits = [" << startingFracBits << "->" << m_fracBits << "]\n"; + + if (g_debugCounter >= debugEncoderSearchBinTargetLine) + { + Char breakPointThis; + breakPointThis = 7; + } + if (g_debugCounter >= (debugEncoderSearchBinTargetLine + debugEncoderSearchBinWindow)) exit(0); + g_debugCounter++; +#endif +} + +/** + * \brief Encode equiprobable bin + * + * \param binValue bin value + */ +Void TEncBinCABACCounter::encodeBinEP( UInt binValue ) +{ + m_uiBinsCoded += m_binCountIncrement; + m_fracBits += 32768; +} + +/** + * \brief Encode equiprobable bins + * + * \param binValues bin values + * \param numBins number of bins + */ +Void TEncBinCABACCounter::encodeBinsEP( UInt binValues, Int numBins ) +{ + m_uiBinsCoded += numBins & -m_binCountIncrement; + m_fracBits += 32768 * numBins; +} + +/** + * \brief Encode terminating bin + * + * \param binValue bin value + */ +Void TEncBinCABACCounter::encodeBinTrm( UInt binValue ) +{ + m_uiBinsCoded += m_binCountIncrement; + m_fracBits += ContextModel::getEntropyBitsTrm( binValue ); +} + +Void TEncBinCABACCounter::align() +{ + m_fracBits = (m_fracBits + 32767) & (~32767); +} + +//! \} +#endif + diff --git a/jctvc/TLibEncoder/TEncBinCoderCABACCounter.h b/jctvc/TLibEncoder/TEncBinCoderCABACCounter.h new file mode 100644 index 0000000..2a38272 --- /dev/null +++ b/jctvc/TLibEncoder/TEncBinCoderCABACCounter.h @@ -0,0 +1,74 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncBinCoderCABAC.h + \brief binary entropy encoder of CABAC +*/ + +#ifndef __TENCBINCODERCABACCOUNTER__ +#define __TENCBINCODERCABACCOUNTER__ + + +#include "TEncBinCoderCABAC.h" + +#if FAST_BIT_EST + +//! \ingroup TLibEncoder +//! \{ + + +class TEncBinCABACCounter : public TEncBinCABAC +{ +public: + TEncBinCABACCounter (); + virtual ~TEncBinCABACCounter(); + + Void finish (); + UInt getNumWrittenBits (); + + Void encodeBin ( UInt binValue, ContextModel& rcCtxModel ); + Void encodeBinEP ( UInt binValue ); + Void encodeBinsEP ( UInt binValues, Int numBins ); + Void encodeBinTrm ( UInt binValue ); + + Void align (); + +private: +}; + +//! \} + +#endif + +#endif + diff --git a/jctvc/TLibEncoder/TEncCavlc.cpp b/jctvc/TLibEncoder/TEncCavlc.cpp new file mode 100644 index 0000000..057daf6 --- /dev/null +++ b/jctvc/TLibEncoder/TEncCavlc.cpp @@ -0,0 +1,1508 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncCavlc.cpp + \brief CAVLC encoder class +*/ + +#include "../TLibCommon/CommonDef.h" +#include "TEncCavlc.h" +#include "SEIwrite.h" + +//! \ingroup TLibEncoder +//! \{ + +#if ENC_DEC_TRACE + +Void xTraceSPSHeader (TComSPS *pSPS) +{ + fprintf( g_hTrace, "=========== Sequence Parameter Set ID: %d ===========\n", pSPS->getSPSId() ); +} + +Void xTracePPSHeader (TComPPS *pPPS) +{ + fprintf( g_hTrace, "=========== Picture Parameter Set ID: %d ===========\n", pPPS->getPPSId() ); +} + +Void xTraceSliceHeader (TComSlice *pSlice) +{ + fprintf( g_hTrace, "=========== Slice ===========\n"); +} + +#endif + + + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TEncCavlc::TEncCavlc() +{ + m_pcBitIf = NULL; +} + +TEncCavlc::~TEncCavlc() +{ +} + + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +Void TEncCavlc::resetEntropy() +{ +} + + +Void TEncCavlc::codeDFFlag(UInt uiCode, const Char *pSymbolName) +{ + WRITE_FLAG(uiCode, pSymbolName); +} +Void TEncCavlc::codeDFSvlc(Int iCode, const Char *pSymbolName) +{ + WRITE_SVLC(iCode, pSymbolName); +} + +Void TEncCavlc::codeShortTermRefPicSet( TComSPS* pcSPS, TComReferencePictureSet* rps, Bool calledFromSliceHeader, Int idx) +{ +#if PRINT_RPS_INFO + Int lastBits = getNumberOfWrittenBits(); +#endif + if (idx > 0) + { + WRITE_FLAG( rps->getInterRPSPrediction(), "inter_ref_pic_set_prediction_flag" ); // inter_RPS_prediction_flag + } + if (rps->getInterRPSPrediction()) + { + Int deltaRPS = rps->getDeltaRPS(); + if(calledFromSliceHeader) + { + WRITE_UVLC( rps->getDeltaRIdxMinus1(), "delta_idx_minus1" ); // delta index of the Reference Picture Set used for prediction minus 1 + } + + WRITE_CODE( (deltaRPS >=0 ? 0: 1), 1, "delta_rps_sign" ); //delta_rps_sign + WRITE_UVLC( abs(deltaRPS) - 1, "abs_delta_rps_minus1"); // absolute delta RPS minus 1 + + for(Int j=0; j < rps->getNumRefIdc(); j++) + { + Int refIdc = rps->getRefIdc(j); + WRITE_CODE( (refIdc==1? 1: 0), 1, "used_by_curr_pic_flag" ); //first bit is "1" if Idc is 1 + if (refIdc != 1) + { + WRITE_CODE( refIdc>>1, 1, "use_delta_flag" ); //second bit is "1" if Idc is 2, "0" otherwise. + } + } + } + else + { + WRITE_UVLC( rps->getNumberOfNegativePictures(), "num_negative_pics" ); + WRITE_UVLC( rps->getNumberOfPositivePictures(), "num_positive_pics" ); + Int prev = 0; + for(Int j=0 ; j < rps->getNumberOfNegativePictures(); j++) + { + WRITE_UVLC( prev-rps->getDeltaPOC(j)-1, "delta_poc_s0_minus1" ); + prev = rps->getDeltaPOC(j); + WRITE_FLAG( rps->getUsed(j), "used_by_curr_pic_s0_flag"); + } + prev = 0; + for(Int j=rps->getNumberOfNegativePictures(); j < rps->getNumberOfNegativePictures()+rps->getNumberOfPositivePictures(); j++) + { + WRITE_UVLC( rps->getDeltaPOC(j)-prev-1, "delta_poc_s1_minus1" ); + prev = rps->getDeltaPOC(j); + WRITE_FLAG( rps->getUsed(j), "used_by_curr_pic_s1_flag" ); + } + } + +#if PRINT_RPS_INFO + printf("irps=%d (%2d bits) ", rps->getInterRPSPrediction(), getNumberOfWrittenBits() - lastBits); + rps->printDeltaPOC(); +#endif +} + + +Void TEncCavlc::codePPS( TComPPS* pcPPS ) +{ +#if ENC_DEC_TRACE + xTracePPSHeader (pcPPS); +#endif + + const UInt numberValidComponents = getNumberValidComponents(pcPPS->getSPS()->getChromaFormatIdc()); + + WRITE_UVLC( pcPPS->getPPSId(), "pps_pic_parameter_set_id" ); + WRITE_UVLC( pcPPS->getSPSId(), "pps_seq_parameter_set_id" ); + WRITE_FLAG( pcPPS->getDependentSliceSegmentsEnabledFlag() ? 1 : 0, "dependent_slice_segments_enabled_flag" ); + WRITE_FLAG( pcPPS->getOutputFlagPresentFlag() ? 1 : 0, "output_flag_present_flag" ); + WRITE_CODE( pcPPS->getNumExtraSliceHeaderBits(), 3, "num_extra_slice_header_bits"); + WRITE_FLAG( pcPPS->getSignHideFlag(), "sign_data_hiding_flag" ); + WRITE_FLAG( pcPPS->getCabacInitPresentFlag() ? 1 : 0, "cabac_init_present_flag" ); + WRITE_UVLC( pcPPS->getNumRefIdxL0DefaultActive()-1, "num_ref_idx_l0_default_active_minus1"); + WRITE_UVLC( pcPPS->getNumRefIdxL1DefaultActive()-1, "num_ref_idx_l1_default_active_minus1"); + + WRITE_SVLC( pcPPS->getPicInitQPMinus26(), "init_qp_minus26"); + WRITE_FLAG( pcPPS->getConstrainedIntraPred() ? 1 : 0, "constrained_intra_pred_flag" ); + WRITE_FLAG( pcPPS->getUseTransformSkip() ? 1 : 0, "transform_skip_enabled_flag" ); + WRITE_FLAG( pcPPS->getUseDQP() ? 1 : 0, "cu_qp_delta_enabled_flag" ); + if ( pcPPS->getUseDQP() ) + { + WRITE_UVLC( pcPPS->getMaxCuDQPDepth(), "diff_cu_qp_delta_depth" ); + } + + WRITE_SVLC( COMPONENT_CbgetQpOffset(COMPONENT_Cb)) : 0, "pps_cb_qp_offset" ); + WRITE_SVLC( COMPONENT_CrgetQpOffset(COMPONENT_Cr)) : 0, "pps_cr_qp_offset" ); + + assert(numberValidComponents <= 3); // if more than 3 components (eg 4:4:4:4), then additional offsets will have to go in extension area... + + WRITE_FLAG( pcPPS->getSliceChromaQpFlag() ? 1 : 0, "pps_slice_chroma_qp_offsets_present_flag" ); + + WRITE_FLAG( pcPPS->getUseWP() ? 1 : 0, "weighted_pred_flag" ); // Use of Weighting Prediction (P_SLICE) + WRITE_FLAG( pcPPS->getWPBiPred() ? 1 : 0, "weighted_bipred_flag" ); // Use of Weighting Bi-Prediction (B_SLICE) + WRITE_FLAG( pcPPS->getTransquantBypassEnableFlag() ? 1 : 0, "transquant_bypass_enable_flag" ); + WRITE_FLAG( pcPPS->getTilesEnabledFlag() ? 1 : 0, "tiles_enabled_flag" ); + WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" ); + if( pcPPS->getTilesEnabledFlag() ) + { + WRITE_UVLC( pcPPS->getNumTileColumnsMinus1(), "num_tile_columns_minus1" ); + WRITE_UVLC( pcPPS->getNumTileRowsMinus1(), "num_tile_rows_minus1" ); + WRITE_FLAG( pcPPS->getTileUniformSpacingFlag(), "uniform_spacing_flag" ); + if( !pcPPS->getTileUniformSpacingFlag() ) + { + for(UInt i=0; igetNumTileColumnsMinus1(); i++) + { + WRITE_UVLC( pcPPS->getTileColumnWidth(i)-1, "column_width_minus1" ); + } + for(UInt i=0; igetNumTileRowsMinus1(); i++) + { + WRITE_UVLC( pcPPS->getTileRowHeight(i)-1, "row_height_minus1" ); + } + } + if(pcPPS->getNumTileColumnsMinus1() !=0 || pcPPS->getNumTileRowsMinus1() !=0) + { + WRITE_FLAG( pcPPS->getLoopFilterAcrossTilesEnabledFlag()?1 : 0, "loop_filter_across_tiles_enabled_flag"); + } + } + WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag()?1 : 0, "loop_filter_across_slices_enabled_flag"); + WRITE_FLAG( pcPPS->getDeblockingFilterControlPresentFlag()?1 : 0, "deblocking_filter_control_present_flag"); + if(pcPPS->getDeblockingFilterControlPresentFlag()) + { + WRITE_FLAG( pcPPS->getDeblockingFilterOverrideEnabledFlag() ? 1 : 0, "deblocking_filter_override_enabled_flag" ); + WRITE_FLAG( pcPPS->getPicDisableDeblockingFilterFlag() ? 1 : 0, "pps_disable_deblocking_filter_flag" ); + if(!pcPPS->getPicDisableDeblockingFilterFlag()) + { + WRITE_SVLC( pcPPS->getDeblockingFilterBetaOffsetDiv2(), "pps_beta_offset_div2" ); + WRITE_SVLC( pcPPS->getDeblockingFilterTcOffsetDiv2(), "pps_tc_offset_div2" ); + } + } + WRITE_FLAG( pcPPS->getScalingListPresentFlag() ? 1 : 0, "pps_scaling_list_data_present_flag" ); + if( pcPPS->getScalingListPresentFlag() ) + { + codeScalingList( m_pcSlice->getScalingList() ); + } + WRITE_FLAG( pcPPS->getListsModificationPresentFlag(), "lists_modification_present_flag"); + WRITE_UVLC( pcPPS->getLog2ParallelMergeLevelMinus2(), "log2_parallel_merge_level_minus2"); + WRITE_FLAG( pcPPS->getSliceHeaderExtensionPresentFlag() ? 1 : 0, "slice_segment_header_extension_present_flag"); + + Bool pps_extension_present_flag=false; + Bool pps_extension_flags[NUM_PPS_EXTENSION_FLAGS]={false}; + + pps_extension_flags[PPS_EXT__REXT] = ( + ( pcPPS->getUseTransformSkip() && (pcPPS->getTransformSkipLog2MaxSize() != 2)) + || pcPPS->getUseCrossComponentPrediction() + || ( pcPPS->getChromaQpAdjTableSize() > 0 ) + || ( pcPPS->getSaoOffsetBitShift(CHANNEL_TYPE_LUMA) !=0 ) || ( pcPPS->getSaoOffsetBitShift(CHANNEL_TYPE_CHROMA) !=0 ) + ) + ; + + // Other PPS extension flags checked here. + + for(Int i=0; igetUseTransformSkip()) + { + WRITE_UVLC( pcPPS->getTransformSkipLog2MaxSize()-2, "log2_transform_skip_max_size_minus2"); + } + + WRITE_FLAG((pcPPS->getUseCrossComponentPrediction() ? 1 : 0), "cross_component_prediction_flag" ); + + WRITE_FLAG(UInt(pcPPS->getChromaQpAdjTableSize() > 0), "chroma_qp_adjustment_enabled_flag" ); + if (pcPPS->getChromaQpAdjTableSize() > 0) + { + WRITE_UVLC(pcPPS->getMaxCuChromaQpAdjDepth(), "diff_cu_chroma_qp_adjustment_depth"); + WRITE_UVLC(pcPPS->getChromaQpAdjTableSize() - 1, "chroma_qp_adjustment_table_size_minus1"); + /* skip zero index */ + for (Int chromaQpAdjustmentIndex = 1; chromaQpAdjustmentIndex <= pcPPS->getChromaQpAdjTableSize(); chromaQpAdjustmentIndex++) + { + WRITE_SVLC(pcPPS->getChromaQpAdjTableAt(chromaQpAdjustmentIndex).u.comp.CbOffset, "cb_qp_adjustnemt[i]"); + WRITE_SVLC(pcPPS->getChromaQpAdjTableAt(chromaQpAdjustmentIndex).u.comp.CrOffset, "cr_qp_adjustnemt[i]"); + } + } + + WRITE_UVLC( pcPPS->getSaoOffsetBitShift(CHANNEL_TYPE_LUMA), "sao_luma_bit_shift" ); + WRITE_UVLC( pcPPS->getSaoOffsetBitShift(CHANNEL_TYPE_CHROMA), "sao_chroma_bit_shift" ); + break; + default: + assert(pps_extension_flags[i]==false); // Should never get here with an active PPS extension flag. + break; + } // switch + } // if flag present + } // loop over PPS flags + } // pps_extension_present_flag is non-zero +} + +Void TEncCavlc::codeVUI( TComVUI *pcVUI, TComSPS* pcSPS ) +{ +#if ENC_DEC_TRACE + fprintf( g_hTrace, "----------- vui_parameters -----------\n"); +#endif + WRITE_FLAG(pcVUI->getAspectRatioInfoPresentFlag(), "aspect_ratio_info_present_flag"); + if (pcVUI->getAspectRatioInfoPresentFlag()) + { + WRITE_CODE(pcVUI->getAspectRatioIdc(), 8, "aspect_ratio_idc" ); + if (pcVUI->getAspectRatioIdc() == 255) + { + WRITE_CODE(pcVUI->getSarWidth(), 16, "sar_width"); + WRITE_CODE(pcVUI->getSarHeight(), 16, "sar_height"); + } + } + WRITE_FLAG(pcVUI->getOverscanInfoPresentFlag(), "overscan_info_present_flag"); + if (pcVUI->getOverscanInfoPresentFlag()) + { + WRITE_FLAG(pcVUI->getOverscanAppropriateFlag(), "overscan_appropriate_flag"); + } + WRITE_FLAG(pcVUI->getVideoSignalTypePresentFlag(), "video_signal_type_present_flag"); + if (pcVUI->getVideoSignalTypePresentFlag()) + { + WRITE_CODE(pcVUI->getVideoFormat(), 3, "video_format"); + WRITE_FLAG(pcVUI->getVideoFullRangeFlag(), "video_full_range_flag"); + WRITE_FLAG(pcVUI->getColourDescriptionPresentFlag(), "colour_description_present_flag"); + if (pcVUI->getColourDescriptionPresentFlag()) + { + WRITE_CODE(pcVUI->getColourPrimaries(), 8, "colour_primaries"); + WRITE_CODE(pcVUI->getTransferCharacteristics(), 8, "transfer_characteristics"); + WRITE_CODE(pcVUI->getMatrixCoefficients(), 8, "matrix_coefficients"); + } + } + + WRITE_FLAG(pcVUI->getChromaLocInfoPresentFlag(), "chroma_loc_info_present_flag"); + if (pcVUI->getChromaLocInfoPresentFlag()) + { + WRITE_UVLC(pcVUI->getChromaSampleLocTypeTopField(), "chroma_sample_loc_type_top_field"); + WRITE_UVLC(pcVUI->getChromaSampleLocTypeBottomField(), "chroma_sample_loc_type_bottom_field"); + } + + WRITE_FLAG(pcVUI->getNeutralChromaIndicationFlag(), "neutral_chroma_indication_flag"); + WRITE_FLAG(pcVUI->getFieldSeqFlag(), "field_seq_flag"); + WRITE_FLAG(pcVUI->getFrameFieldInfoPresentFlag(), "frame_field_info_present_flag"); + + Window defaultDisplayWindow = pcVUI->getDefaultDisplayWindow(); + WRITE_FLAG(defaultDisplayWindow.getWindowEnabledFlag(), "default_display_window_flag"); + if( defaultDisplayWindow.getWindowEnabledFlag() ) + { + WRITE_UVLC(defaultDisplayWindow.getWindowLeftOffset() / TComSPS::getWinUnitX(pcSPS->getChromaFormatIdc()), "def_disp_win_left_offset"); + WRITE_UVLC(defaultDisplayWindow.getWindowRightOffset() / TComSPS::getWinUnitX(pcSPS->getChromaFormatIdc()), "def_disp_win_right_offset"); + WRITE_UVLC(defaultDisplayWindow.getWindowTopOffset() / TComSPS::getWinUnitY(pcSPS->getChromaFormatIdc()), "def_disp_win_top_offset"); + WRITE_UVLC(defaultDisplayWindow.getWindowBottomOffset()/ TComSPS::getWinUnitY(pcSPS->getChromaFormatIdc()), "def_disp_win_bottom_offset"); + } + TimingInfo *timingInfo = pcVUI->getTimingInfo(); + WRITE_FLAG(timingInfo->getTimingInfoPresentFlag(), "vui_timing_info_present_flag"); + if(timingInfo->getTimingInfoPresentFlag()) + { + WRITE_CODE(timingInfo->getNumUnitsInTick(), 32, "vui_num_units_in_tick"); + WRITE_CODE(timingInfo->getTimeScale(), 32, "vui_time_scale"); + WRITE_FLAG(timingInfo->getPocProportionalToTimingFlag(), "vui_poc_proportional_to_timing_flag"); + if(timingInfo->getPocProportionalToTimingFlag()) + { + WRITE_UVLC(timingInfo->getNumTicksPocDiffOneMinus1(), "vui_num_ticks_poc_diff_one_minus1"); + } + WRITE_FLAG(pcVUI->getHrdParametersPresentFlag(), "hrd_parameters_present_flag"); + if( pcVUI->getHrdParametersPresentFlag() ) + { + codeHrdParameters(pcVUI->getHrdParameters(), 1, pcSPS->getMaxTLayers() - 1 ); + } + } + + WRITE_FLAG(pcVUI->getBitstreamRestrictionFlag(), "bitstream_restriction_flag"); + if (pcVUI->getBitstreamRestrictionFlag()) + { + WRITE_FLAG(pcVUI->getTilesFixedStructureFlag(), "tiles_fixed_structure_flag"); + WRITE_FLAG(pcVUI->getMotionVectorsOverPicBoundariesFlag(), "motion_vectors_over_pic_boundaries_flag"); + WRITE_FLAG(pcVUI->getRestrictedRefPicListsFlag(), "restricted_ref_pic_lists_flag"); + WRITE_UVLC(pcVUI->getMinSpatialSegmentationIdc(), "min_spatial_segmentation_idc"); + WRITE_UVLC(pcVUI->getMaxBytesPerPicDenom(), "max_bytes_per_pic_denom"); + WRITE_UVLC(pcVUI->getMaxBitsPerMinCuDenom(), "max_bits_per_mincu_denom"); + WRITE_UVLC(pcVUI->getLog2MaxMvLengthHorizontal(), "log2_max_mv_length_horizontal"); + WRITE_UVLC(pcVUI->getLog2MaxMvLengthVertical(), "log2_max_mv_length_vertical"); + } +} + +Void TEncCavlc::codeHrdParameters( TComHRD *hrd, Bool commonInfPresentFlag, UInt maxNumSubLayersMinus1 ) +{ + if( commonInfPresentFlag ) + { + WRITE_FLAG( hrd->getNalHrdParametersPresentFlag() ? 1 : 0 , "nal_hrd_parameters_present_flag" ); + WRITE_FLAG( hrd->getVclHrdParametersPresentFlag() ? 1 : 0 , "vcl_hrd_parameters_present_flag" ); + if( hrd->getNalHrdParametersPresentFlag() || hrd->getVclHrdParametersPresentFlag() ) + { + WRITE_FLAG( hrd->getSubPicCpbParamsPresentFlag() ? 1 : 0, "sub_pic_cpb_params_present_flag" ); + if( hrd->getSubPicCpbParamsPresentFlag() ) + { + WRITE_CODE( hrd->getTickDivisorMinus2(), 8, "tick_divisor_minus2" ); + WRITE_CODE( hrd->getDuCpbRemovalDelayLengthMinus1(), 5, "du_cpb_removal_delay_length_minus1" ); + WRITE_FLAG( hrd->getSubPicCpbParamsInPicTimingSEIFlag() ? 1 : 0, "sub_pic_cpb_params_in_pic_timing_sei_flag" ); + WRITE_CODE( hrd->getDpbOutputDelayDuLengthMinus1(), 5, "dpb_output_delay_du_length_minus1" ); + } + WRITE_CODE( hrd->getBitRateScale(), 4, "bit_rate_scale" ); + WRITE_CODE( hrd->getCpbSizeScale(), 4, "cpb_size_scale" ); + if( hrd->getSubPicCpbParamsPresentFlag() ) + { + WRITE_CODE( hrd->getDuCpbSizeScale(), 4, "du_cpb_size_scale" ); + } + WRITE_CODE( hrd->getInitialCpbRemovalDelayLengthMinus1(), 5, "initial_cpb_removal_delay_length_minus1" ); + WRITE_CODE( hrd->getCpbRemovalDelayLengthMinus1(), 5, "au_cpb_removal_delay_length_minus1" ); + WRITE_CODE( hrd->getDpbOutputDelayLengthMinus1(), 5, "dpb_output_delay_length_minus1" ); + } + } + Int i, j, nalOrVcl; + for( i = 0; i <= maxNumSubLayersMinus1; i ++ ) + { + WRITE_FLAG( hrd->getFixedPicRateFlag( i ) ? 1 : 0, "fixed_pic_rate_general_flag"); + if( !hrd->getFixedPicRateFlag( i ) ) + { + WRITE_FLAG( hrd->getFixedPicRateWithinCvsFlag( i ) ? 1 : 0, "fixed_pic_rate_within_cvs_flag"); + } + else + { + hrd->setFixedPicRateWithinCvsFlag( i, true ); + } + if( hrd->getFixedPicRateWithinCvsFlag( i ) ) + { + WRITE_UVLC( hrd->getPicDurationInTcMinus1( i ), "elemental_duration_in_tc_minus1"); + } + else + { + WRITE_FLAG( hrd->getLowDelayHrdFlag( i ) ? 1 : 0, "low_delay_hrd_flag"); + } + if (!hrd->getLowDelayHrdFlag( i )) + { + WRITE_UVLC( hrd->getCpbCntMinus1( i ), "cpb_cnt_minus1"); + } + + for( nalOrVcl = 0; nalOrVcl < 2; nalOrVcl ++ ) + { + if( ( ( nalOrVcl == 0 ) && ( hrd->getNalHrdParametersPresentFlag() ) ) || + ( ( nalOrVcl == 1 ) && ( hrd->getVclHrdParametersPresentFlag() ) ) ) + { + for( j = 0; j <= ( hrd->getCpbCntMinus1( i ) ); j ++ ) + { + WRITE_UVLC( hrd->getBitRateValueMinus1( i, j, nalOrVcl ), "bit_rate_value_minus1"); + WRITE_UVLC( hrd->getCpbSizeValueMinus1( i, j, nalOrVcl ), "cpb_size_value_minus1"); + if( hrd->getSubPicCpbParamsPresentFlag() ) + { + WRITE_UVLC( hrd->getDuCpbSizeValueMinus1( i, j, nalOrVcl ), "cpb_size_du_value_minus1"); + WRITE_UVLC( hrd->getDuBitRateValueMinus1( i, j, nalOrVcl ), "bit_rate_du_value_minus1"); + } + WRITE_FLAG( hrd->getCbrFlag( i, j, nalOrVcl ) ? 1 : 0, "cbr_flag"); + } + } + } + } +} + +Void TEncCavlc::codeSPS( TComSPS* pcSPS ) +{ + + const ChromaFormat format = pcSPS->getChromaFormatIdc(); + const Bool chromaEnabled = isChromaEnabled(format); + +#if ENC_DEC_TRACE + xTraceSPSHeader (pcSPS); +#endif + WRITE_CODE( pcSPS->getVPSId (), 4, "sps_video_parameter_set_id" ); + WRITE_CODE( pcSPS->getMaxTLayers() - 1, 3, "sps_max_sub_layers_minus1" ); + WRITE_FLAG( pcSPS->getTemporalIdNestingFlag() ? 1 : 0, "sps_temporal_id_nesting_flag" ); + codePTL(pcSPS->getPTL(), 1, pcSPS->getMaxTLayers() - 1); + WRITE_UVLC( pcSPS->getSPSId (), "sps_seq_parameter_set_id" ); + WRITE_UVLC( Int(pcSPS->getChromaFormatIdc ()), "chroma_format_idc" ); + if( format == CHROMA_444 ) + { + WRITE_FLAG( 0, "separate_colour_plane_flag"); + } + + WRITE_UVLC( pcSPS->getPicWidthInLumaSamples (), "pic_width_in_luma_samples" ); + WRITE_UVLC( pcSPS->getPicHeightInLumaSamples(), "pic_height_in_luma_samples" ); + Window conf = pcSPS->getConformanceWindow(); + + WRITE_FLAG( conf.getWindowEnabledFlag(), "conformance_window_flag" ); + if (conf.getWindowEnabledFlag()) + { + WRITE_UVLC( conf.getWindowLeftOffset() / TComSPS::getWinUnitX(pcSPS->getChromaFormatIdc() ), "conf_win_left_offset" ); + WRITE_UVLC( conf.getWindowRightOffset() / TComSPS::getWinUnitX(pcSPS->getChromaFormatIdc() ), "conf_win_right_offset" ); + WRITE_UVLC( conf.getWindowTopOffset() / TComSPS::getWinUnitY(pcSPS->getChromaFormatIdc() ), "conf_win_top_offset" ); + WRITE_UVLC( conf.getWindowBottomOffset() / TComSPS::getWinUnitY(pcSPS->getChromaFormatIdc() ), "conf_win_bottom_offset" ); + } + + WRITE_UVLC( pcSPS->getBitDepth(CHANNEL_TYPE_LUMA) - 8, "bit_depth_luma_minus8" ); + + WRITE_UVLC( chromaEnabled ? (pcSPS->getBitDepth(CHANNEL_TYPE_CHROMA) - 8):0, "bit_depth_chroma_minus8" ); + + WRITE_UVLC( pcSPS->getBitsForPOC()-4, "log2_max_pic_order_cnt_lsb_minus4" ); + + const Bool subLayerOrderingInfoPresentFlag = 1; + WRITE_FLAG(subLayerOrderingInfoPresentFlag, "sps_sub_layer_ordering_info_present_flag"); + for(UInt i=0; i <= pcSPS->getMaxTLayers()-1; i++) + { + WRITE_UVLC( pcSPS->getMaxDecPicBuffering(i) - 1, "sps_max_dec_pic_buffering_minus1[i]" ); + WRITE_UVLC( pcSPS->getNumReorderPics(i), "sps_num_reorder_pics[i]" ); + WRITE_UVLC( pcSPS->getMaxLatencyIncrease(i), "sps_max_latency_increase_plus1[i]" ); + if (!subLayerOrderingInfoPresentFlag) + { + break; + } + } + assert( pcSPS->getMaxCUWidth() == pcSPS->getMaxCUHeight() ); + + WRITE_UVLC( pcSPS->getLog2MinCodingBlockSize() - 3, "log2_min_coding_block_size_minus3" ); + WRITE_UVLC( pcSPS->getLog2DiffMaxMinCodingBlockSize(), "log2_diff_max_min_coding_block_size" ); + WRITE_UVLC( pcSPS->getQuadtreeTULog2MinSize() - 2, "log2_min_transform_block_size_minus2" ); + WRITE_UVLC( pcSPS->getQuadtreeTULog2MaxSize() - pcSPS->getQuadtreeTULog2MinSize(), "log2_diff_max_min_transform_block_size" ); + WRITE_UVLC( pcSPS->getQuadtreeTUMaxDepthInter() - 1, "max_transform_hierarchy_depth_inter" ); + WRITE_UVLC( pcSPS->getQuadtreeTUMaxDepthIntra() - 1, "max_transform_hierarchy_depth_intra" ); + WRITE_FLAG( pcSPS->getScalingListFlag() ? 1 : 0, "scaling_list_enabled_flag" ); + if(pcSPS->getScalingListFlag()) + { + WRITE_FLAG( pcSPS->getScalingListPresentFlag() ? 1 : 0, "sps_scaling_list_data_present_flag" ); + if(pcSPS->getScalingListPresentFlag()) + { + codeScalingList( m_pcSlice->getScalingList() ); + } + } + WRITE_FLAG( pcSPS->getUseAMP() ? 1 : 0, "amp_enabled_flag" ); + WRITE_FLAG( pcSPS->getUseSAO() ? 1 : 0, "sample_adaptive_offset_enabled_flag"); + + WRITE_FLAG( pcSPS->getUsePCM() ? 1 : 0, "pcm_enabled_flag"); + if( pcSPS->getUsePCM() ) + { + WRITE_CODE( pcSPS->getPCMBitDepth(CHANNEL_TYPE_LUMA) - 1, 4, "pcm_sample_bit_depth_luma_minus1" ); + WRITE_CODE( chromaEnabled ? (pcSPS->getPCMBitDepth(CHANNEL_TYPE_CHROMA) - 1) : 0, 4, "pcm_sample_bit_depth_chroma_minus1" ); + WRITE_UVLC( pcSPS->getPCMLog2MinSize() - 3, "log2_min_pcm_luma_coding_block_size_minus3" ); + WRITE_UVLC( pcSPS->getPCMLog2MaxSize() - pcSPS->getPCMLog2MinSize(), "log2_diff_max_min_pcm_luma_coding_block_size" ); + WRITE_FLAG( pcSPS->getPCMFilterDisableFlag()?1 : 0, "pcm_loop_filter_disable_flag"); + } + + assert( pcSPS->getMaxTLayers() > 0 ); + + TComRPSList* rpsList = pcSPS->getRPSList(); + TComReferencePictureSet* rps; + + if (1) { + WRITE_UVLC(0, "num_short_term_ref_pic_sets" ); + } else { + WRITE_UVLC(rpsList->getNumberOfReferencePictureSets(), "num_short_term_ref_pic_sets" ); + for(Int i=0; i < rpsList->getNumberOfReferencePictureSets(); i++) + { + rps = rpsList->getReferencePictureSet(i); + codeShortTermRefPicSet(pcSPS,rps,false, i); + } + } + WRITE_FLAG( pcSPS->getLongTermRefsPresent() ? 1 : 0, "long_term_ref_pics_present_flag" ); + if (pcSPS->getLongTermRefsPresent()) + { + WRITE_UVLC(pcSPS->getNumLongTermRefPicSPS(), "num_long_term_ref_pic_sps" ); + for (UInt k = 0; k < pcSPS->getNumLongTermRefPicSPS(); k++) + { + WRITE_CODE( pcSPS->getLtRefPicPocLsbSps(k), pcSPS->getBitsForPOC(), "lt_ref_pic_poc_lsb_sps"); + WRITE_FLAG( pcSPS->getUsedByCurrPicLtSPSFlag(k), "used_by_curr_pic_lt_sps_flag"); + } + } + WRITE_FLAG( pcSPS->getTMVPFlagsPresent() ? 1 : 0, "sps_temporal_mvp_enable_flag" ); + + WRITE_FLAG( pcSPS->getUseStrongIntraSmoothing(), "sps_strong_intra_smoothing_enable_flag" ); + + WRITE_FLAG( pcSPS->getVuiParametersPresentFlag(), "vui_parameters_present_flag" ); + if (pcSPS->getVuiParametersPresentFlag()) + { + codeVUI(pcSPS->getVuiParameters(), pcSPS); + } + + Bool sps_extension_present_flag=false; + Bool sps_extension_flags[NUM_SPS_EXTENSION_FLAGS]={false}; + + sps_extension_flags[SPS_EXT__REXT] = ( + pcSPS->getUseResidualRotation() + || pcSPS->getUseSingleSignificanceMapContext() + || pcSPS->getUseResidualDPCM(RDPCM_SIGNAL_IMPLICIT) + || pcSPS->getUseResidualDPCM(RDPCM_SIGNAL_EXPLICIT) + || pcSPS->getUseExtendedPrecision() + || pcSPS->getDisableIntraReferenceSmoothing() + || pcSPS->getUseHighPrecisionPredictionWeighting() + || pcSPS->getUseGolombRiceParameterAdaptation() + || pcSPS->getAlignCABACBeforeBypass() + ); + + // Other SPS extension flags checked here. + + for(Int i=0; igetUseResidualRotation() ? 1 : 0), "transform_skip_rotation_enabled_flag"); + WRITE_FLAG( (pcSPS->getUseSingleSignificanceMapContext() ? 1 : 0), "transform_skip_context_enabled_flag"); + WRITE_FLAG( (pcSPS->getUseResidualDPCM(RDPCM_SIGNAL_IMPLICIT) ? 1 : 0), "residual_dpcm_implicit_enabled_flag" ); + WRITE_FLAG( (pcSPS->getUseResidualDPCM(RDPCM_SIGNAL_EXPLICIT) ? 1 : 0), "residual_dpcm_explicit_enabled_flag" ); + WRITE_FLAG( (pcSPS->getUseExtendedPrecision() ? 1 : 0), "extended_precision_processing_flag" ); + WRITE_FLAG( (pcSPS->getDisableIntraReferenceSmoothing() ? 1 : 0), "intra_smoothing_disabled_flag" ); + WRITE_FLAG( (pcSPS->getUseHighPrecisionPredictionWeighting() ? 1 : 0), "high_precision_prediction_weighting_flag" ); + WRITE_FLAG( (pcSPS->getUseGolombRiceParameterAdaptation() ? 1 : 0), "golomb_rice_parameter_adaptation_flag" ); + WRITE_FLAG( (pcSPS->getAlignCABACBeforeBypass() ? 1 : 0), "cabac_bypass_alignment_enabled_flag" ); + break; + default: + assert(sps_extension_flags[i]==false); // Should never get here with an active SPS extension flag. + break; + } + } + } + } +} + +Void TEncCavlc::codeVPS( TComVPS* pcVPS ) +{ + WRITE_CODE( pcVPS->getVPSId(), 4, "vps_video_parameter_set_id" ); + WRITE_CODE( 3, 2, "vps_reserved_three_2bits" ); + WRITE_CODE( 0, 6, "vps_reserved_zero_6bits" ); + WRITE_CODE( pcVPS->getMaxTLayers() - 1, 3, "vps_max_sub_layers_minus1" ); + WRITE_FLAG( pcVPS->getTemporalNestingFlag(), "vps_temporal_id_nesting_flag" ); + assert (pcVPS->getMaxTLayers()>1||pcVPS->getTemporalNestingFlag()); + WRITE_CODE( 0xffff, 16, "vps_reserved_ffff_16bits" ); + codePTL( pcVPS->getPTL(), true, pcVPS->getMaxTLayers() - 1 ); + const Bool subLayerOrderingInfoPresentFlag = 1; + WRITE_FLAG(subLayerOrderingInfoPresentFlag, "vps_sub_layer_ordering_info_present_flag"); + for(UInt i=0; i <= pcVPS->getMaxTLayers()-1; i++) + { + WRITE_UVLC( pcVPS->getMaxDecPicBuffering(i) - 1, "vps_max_dec_pic_buffering_minus1[i]" ); + WRITE_UVLC( pcVPS->getNumReorderPics(i), "vps_num_reorder_pics[i]" ); + WRITE_UVLC( pcVPS->getMaxLatencyIncrease(i), "vps_max_latency_increase_plus1[i]" ); + if (!subLayerOrderingInfoPresentFlag) + { + break; + } + } + + assert( pcVPS->getNumHrdParameters() <= MAX_VPS_NUM_HRD_PARAMETERS ); + assert( pcVPS->getMaxNuhReservedZeroLayerId() < MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 ); + WRITE_CODE( pcVPS->getMaxNuhReservedZeroLayerId(), 6, "vps_max_nuh_reserved_zero_layer_id" ); + pcVPS->setMaxOpSets(1); + WRITE_UVLC( pcVPS->getMaxOpSets() - 1, "vps_max_op_sets_minus1" ); + for( UInt opsIdx = 1; opsIdx <= ( pcVPS->getMaxOpSets() - 1 ); opsIdx ++ ) + { + // Operation point set + for( UInt i = 0; i <= pcVPS->getMaxNuhReservedZeroLayerId(); i ++ ) + { + // Only applicable for version 1 + pcVPS->setLayerIdIncludedFlag( true, opsIdx, i ); + WRITE_FLAG( pcVPS->getLayerIdIncludedFlag( opsIdx, i ) ? 1 : 0, "layer_id_included_flag[opsIdx][i]" ); + } + } + TimingInfo *timingInfo = pcVPS->getTimingInfo(); + WRITE_FLAG(timingInfo->getTimingInfoPresentFlag(), "vps_timing_info_present_flag"); + if(timingInfo->getTimingInfoPresentFlag()) + { + WRITE_CODE(timingInfo->getNumUnitsInTick(), 32, "vps_num_units_in_tick"); + WRITE_CODE(timingInfo->getTimeScale(), 32, "vps_time_scale"); + WRITE_FLAG(timingInfo->getPocProportionalToTimingFlag(), "vps_poc_proportional_to_timing_flag"); + if(timingInfo->getPocProportionalToTimingFlag()) + { + WRITE_UVLC(timingInfo->getNumTicksPocDiffOneMinus1(), "vps_num_ticks_poc_diff_one_minus1"); + } + pcVPS->setNumHrdParameters( 0 ); + WRITE_UVLC( pcVPS->getNumHrdParameters(), "vps_num_hrd_parameters" ); + + if( pcVPS->getNumHrdParameters() > 0 ) + { + pcVPS->createHrdParamBuffer(); + } + for( UInt i = 0; i < pcVPS->getNumHrdParameters(); i ++ ) + { + // Only applicable for version 1 + pcVPS->setHrdOpSetIdx( 0, i ); + WRITE_UVLC( pcVPS->getHrdOpSetIdx( i ), "hrd_op_set_idx" ); + if( i > 0 ) + { + WRITE_FLAG( pcVPS->getCprmsPresentFlag( i ) ? 1 : 0, "cprms_present_flag[i]" ); + } + codeHrdParameters(pcVPS->getHrdParameters(i), pcVPS->getCprmsPresentFlag( i ), pcVPS->getMaxTLayers() - 1); + } + } + WRITE_FLAG( 0, "vps_extension_flag" ); + + //future extensions here.. + + return; +} + +Void TEncCavlc::codeSliceHeader ( TComSlice* pcSlice ) +{ +#if ENC_DEC_TRACE + xTraceSliceHeader (pcSlice); +#endif + + const ChromaFormat format = pcSlice->getSPS()->getChromaFormatIdc(); + const UInt numberValidComponents = getNumberValidComponents(format); + const Bool chromaEnabled = isChromaEnabled(format); + + //calculate number of bits required for slice address + Int maxSliceSegmentAddress = pcSlice->getPic()->getNumberOfCtusInFrame(); + Int bitsSliceSegmentAddress = 0; + while(maxSliceSegmentAddress>(1<getSliceSegmentCurStartCtuTsAddr(); + + //write slice address + const Int sliceSegmentRsAddress = pcSlice->getPic()->getPicSym()->getCtuTsToRsAddrMap(ctuTsAddress); + + WRITE_FLAG( sliceSegmentRsAddress==0, "first_slice_segment_in_pic_flag" ); + if ( pcSlice->getRapPicFlag() ) + { + WRITE_FLAG( pcSlice->getNoOutputPriorPicsFlag() ? 1 : 0, "no_output_of_prior_pics_flag" ); + } + WRITE_UVLC( pcSlice->getPPS()->getPPSId(), "slice_pic_parameter_set_id" ); + if ( pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag() && (sliceSegmentRsAddress!=0) ) + { + WRITE_FLAG( pcSlice->getDependentSliceSegmentFlag() ? 1 : 0, "dependent_slice_segment_flag" ); + } + if(sliceSegmentRsAddress>0) + { + WRITE_CODE( sliceSegmentRsAddress, bitsSliceSegmentAddress, "slice_segment_address" ); + } + if ( !pcSlice->getDependentSliceSegmentFlag() ) + { + for (Int i = 0; i < pcSlice->getPPS()->getNumExtraSliceHeaderBits(); i++) + { + assert(!!"slice_reserved_undetermined_flag[]"); + WRITE_FLAG(0, "slice_reserved_undetermined_flag[]"); + } + + WRITE_UVLC( pcSlice->getSliceType(), "slice_type" ); + + if( pcSlice->getPPS()->getOutputFlagPresentFlag() ) + { + WRITE_FLAG( pcSlice->getPicOutputFlag() ? 1 : 0, "pic_output_flag" ); + } + + if( !pcSlice->getIdrPicFlag() ) + { + Int picOrderCntLSB = (pcSlice->getPOC()-pcSlice->getLastIDR()+(1<getSPS()->getBitsForPOC())) & ((1<getSPS()->getBitsForPOC())-1); + WRITE_CODE( picOrderCntLSB, pcSlice->getSPS()->getBitsForPOC(), "pic_order_cnt_lsb"); + TComReferencePictureSet* rps = pcSlice->getRPS(); + + // check for bitstream restriction stating that: + // If the current picture is a BLA or CRA picture, the value of NumPocTotalCurr shall be equal to 0. + // Ideally this process should not be repeated for each slice in a picture + if (pcSlice->isIRAP()) + { + for (Int picIdx = 0; picIdx < rps->getNumberOfPictures(); picIdx++) + { + assert (!rps->getUsed(picIdx)); + } + } + + if(pcSlice->getRPSidx() < 0) + { + WRITE_FLAG( 0, "short_term_ref_pic_set_sps_flag"); + codeShortTermRefPicSet(pcSlice->getSPS(), rps, true, pcSlice->getSPS()->getRPSList()->getNumberOfReferencePictureSets()); + } + else + { + WRITE_FLAG( 1, "short_term_ref_pic_set_sps_flag"); + Int numBits = 0; + while ((1 << numBits) < pcSlice->getSPS()->getRPSList()->getNumberOfReferencePictureSets()) + { + numBits++; + } + if (numBits > 0) + { + WRITE_CODE( pcSlice->getRPSidx(), numBits, "short_term_ref_pic_set_idx" ); + } + } + if(pcSlice->getSPS()->getLongTermRefsPresent()) + { + Int numLtrpInSH = rps->getNumberOfLongtermPictures(); + Int ltrpInSPS[MAX_NUM_REF_PICS]; + Int numLtrpInSPS = 0; + UInt ltrpIndex; + Int counter = 0; + for(Int k = rps->getNumberOfPictures()-1; k > rps->getNumberOfPictures()-rps->getNumberOfLongtermPictures()-1; k--) + { + if (findMatchingLTRP(pcSlice, <rpIndex, rps->getPOC(k), rps->getUsed(k))) + { + ltrpInSPS[numLtrpInSPS] = ltrpIndex; + numLtrpInSPS++; + } + else + { + counter++; + } + } + numLtrpInSH -= numLtrpInSPS; + + Int bitsForLtrpInSPS = 0; + while (pcSlice->getSPS()->getNumLongTermRefPicSPS() > (1 << bitsForLtrpInSPS)) + { + bitsForLtrpInSPS++; + } + if (pcSlice->getSPS()->getNumLongTermRefPicSPS() > 0) + { + WRITE_UVLC( numLtrpInSPS, "num_long_term_sps"); + } + WRITE_UVLC( numLtrpInSH, "num_long_term_pics"); + // Note that the LSBs of the LT ref. pic. POCs must be sorted before. + // Not sorted here because LT ref indices will be used in setRefPicList() + Int prevDeltaMSB = 0, prevLSB = 0; + Int offset = rps->getNumberOfNegativePictures() + rps->getNumberOfPositivePictures(); + for(Int i=rps->getNumberOfPictures()-1 ; i > offset-1; i--) + { + if (counter < numLtrpInSPS) + { + if (bitsForLtrpInSPS > 0) + { + WRITE_CODE( ltrpInSPS[counter], bitsForLtrpInSPS, "lt_idx_sps[i]"); + } + } + else + { + WRITE_CODE( rps->getPocLSBLT(i), pcSlice->getSPS()->getBitsForPOC(), "poc_lsb_lt"); + WRITE_FLAG( rps->getUsed(i), "used_by_curr_pic_lt_flag"); + } + WRITE_FLAG( rps->getDeltaPocMSBPresentFlag(i), "delta_poc_msb_present_flag"); + + if(rps->getDeltaPocMSBPresentFlag(i)) + { + Bool deltaFlag = false; + // First LTRP from SPS || First LTRP from SH || curr LSB != prev LSB + if( (i == rps->getNumberOfPictures()-1) || (i == rps->getNumberOfPictures()-1-numLtrpInSPS) || (rps->getPocLSBLT(i) != prevLSB) ) + { + deltaFlag = true; + } + if(deltaFlag) + { + WRITE_UVLC( rps->getDeltaPocMSBCycleLT(i), "delta_poc_msb_cycle_lt[i]" ); + } + else + { + Int differenceInDeltaMSB = rps->getDeltaPocMSBCycleLT(i) - prevDeltaMSB; + assert(differenceInDeltaMSB >= 0); + WRITE_UVLC( differenceInDeltaMSB, "delta_poc_msb_cycle_lt[i]" ); + } + prevLSB = rps->getPocLSBLT(i); + prevDeltaMSB = rps->getDeltaPocMSBCycleLT(i); + } + } + } + if (pcSlice->getSPS()->getTMVPFlagsPresent()) + { + WRITE_FLAG( pcSlice->getEnableTMVPFlag() ? 1 : 0, "slice_temporal_mvp_enable_flag" ); + } + } + if(pcSlice->getSPS()->getUseSAO()) + { + WRITE_FLAG( pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_LUMA), "slice_sao_luma_flag" ); + if (chromaEnabled) WRITE_FLAG( pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_CHROMA), "slice_sao_chroma_flag" ); + } + + //check if numrefidxes match the defaults. If not, override + + if (!pcSlice->isIntra()) + { + Bool overrideFlag = (pcSlice->getNumRefIdx( REF_PIC_LIST_0 )!=pcSlice->getPPS()->getNumRefIdxL0DefaultActive()||(pcSlice->isInterB()&&pcSlice->getNumRefIdx( REF_PIC_LIST_1 )!=pcSlice->getPPS()->getNumRefIdxL1DefaultActive())); + WRITE_FLAG( overrideFlag ? 1 : 0, "num_ref_idx_active_override_flag"); + if (overrideFlag) + { + WRITE_UVLC( pcSlice->getNumRefIdx( REF_PIC_LIST_0 ) - 1, "num_ref_idx_l0_active_minus1" ); + if (pcSlice->isInterB()) + { + WRITE_UVLC( pcSlice->getNumRefIdx( REF_PIC_LIST_1 ) - 1, "num_ref_idx_l1_active_minus1" ); + } + else + { + pcSlice->setNumRefIdx(REF_PIC_LIST_1, 0); + } + } + } + else + { + pcSlice->setNumRefIdx(REF_PIC_LIST_0, 0); + pcSlice->setNumRefIdx(REF_PIC_LIST_1, 0); + } + + if( pcSlice->getPPS()->getListsModificationPresentFlag() && pcSlice->getNumRpsCurrTempList() > 1) + { + TComRefPicListModification* refPicListModification = pcSlice->getRefPicListModification(); + if(!pcSlice->isIntra()) + { + WRITE_FLAG(pcSlice->getRefPicListModification()->getRefPicListModificationFlagL0() ? 1 : 0, "ref_pic_list_modification_flag_l0" ); + if (pcSlice->getRefPicListModification()->getRefPicListModificationFlagL0()) + { + Int numRpsCurrTempList0 = pcSlice->getNumRpsCurrTempList(); + if (numRpsCurrTempList0 > 1) + { + Int length = 1; + numRpsCurrTempList0 --; + while ( numRpsCurrTempList0 >>= 1) + { + length ++; + } + for(Int i = 0; i < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); i++) + { + WRITE_CODE( refPicListModification->getRefPicSetIdxL0(i), length, "list_entry_l0"); + } + } + } + } + if(pcSlice->isInterB()) + { + WRITE_FLAG(pcSlice->getRefPicListModification()->getRefPicListModificationFlagL1() ? 1 : 0, "ref_pic_list_modification_flag_l1" ); + if (pcSlice->getRefPicListModification()->getRefPicListModificationFlagL1()) + { + Int numRpsCurrTempList1 = pcSlice->getNumRpsCurrTempList(); + if ( numRpsCurrTempList1 > 1 ) + { + Int length = 1; + numRpsCurrTempList1 --; + while ( numRpsCurrTempList1 >>= 1) + { + length ++; + } + for(Int i = 0; i < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); i++) + { + WRITE_CODE( refPicListModification->getRefPicSetIdxL1(i), length, "list_entry_l1"); + } + } + } + } + } + + if (pcSlice->isInterB()) + { + WRITE_FLAG( pcSlice->getMvdL1ZeroFlag() ? 1 : 0, "mvd_l1_zero_flag"); + } + + if(!pcSlice->isIntra()) + { + if (!pcSlice->isIntra() && pcSlice->getPPS()->getCabacInitPresentFlag()) + { + SliceType sliceType = pcSlice->getSliceType(); + Int encCABACTableIdx = pcSlice->getPPS()->getEncCABACTableIdx(); + Bool encCabacInitFlag = (sliceType!=encCABACTableIdx && encCABACTableIdx!=I_SLICE) ? true : false; + pcSlice->setCabacInitFlag( encCabacInitFlag ); + WRITE_FLAG( encCabacInitFlag?1:0, "cabac_init_flag" ); + } + } + + if ( pcSlice->getEnableTMVPFlag() ) + { + if ( pcSlice->getSliceType() == B_SLICE ) + { + WRITE_FLAG( pcSlice->getColFromL0Flag(), "collocated_from_l0_flag" ); + } + + if ( pcSlice->getSliceType() != I_SLICE && + ((pcSlice->getColFromL0Flag()==1 && pcSlice->getNumRefIdx(REF_PIC_LIST_0)>1)|| + (pcSlice->getColFromL0Flag()==0 && pcSlice->getNumRefIdx(REF_PIC_LIST_1)>1))) + { + WRITE_UVLC( pcSlice->getColRefIdx(), "collocated_ref_idx" ); + } + } + if ( (pcSlice->getPPS()->getUseWP() && pcSlice->getSliceType()==P_SLICE) || (pcSlice->getPPS()->getWPBiPred() && pcSlice->getSliceType()==B_SLICE) ) + { + xCodePredWeightTable( pcSlice ); + } + assert(pcSlice->getMaxNumMergeCand()<=MRG_MAX_NUM_CANDS); + if (!pcSlice->isIntra()) + { + WRITE_UVLC(MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "five_minus_max_num_merge_cand"); + } + Int iCode = pcSlice->getSliceQp() - ( pcSlice->getPPS()->getPicInitQPMinus26() + 26 ); + WRITE_SVLC( iCode, "slice_qp_delta" ); + if (pcSlice->getPPS()->getSliceChromaQpFlag()) + { + if (numberValidComponents > COMPONENT_Cb) { WRITE_SVLC( pcSlice->getSliceChromaQpDelta(COMPONENT_Cb), "slice_qp_delta_cb" ); } + if (numberValidComponents > COMPONENT_Cr) { WRITE_SVLC( pcSlice->getSliceChromaQpDelta(COMPONENT_Cr), "slice_qp_delta_cr" ); } + assert(numberValidComponents <= COMPONENT_Cr+1); + } + + if (pcSlice->getPPS()->getChromaQpAdjTableSize() > 0) + { + WRITE_FLAG(pcSlice->getUseChromaQpAdj(), "slice_chroma_qp_adjustment_enabled_flag"); + } + + if (pcSlice->getPPS()->getDeblockingFilterControlPresentFlag()) + { + if (pcSlice->getPPS()->getDeblockingFilterOverrideEnabledFlag() ) + { + WRITE_FLAG(pcSlice->getDeblockingFilterOverrideFlag(), "deblocking_filter_override_flag"); + } + if (pcSlice->getDeblockingFilterOverrideFlag()) + { + WRITE_FLAG(pcSlice->getDeblockingFilterDisable(), "slice_disable_deblocking_filter_flag"); + if(!pcSlice->getDeblockingFilterDisable()) + { + WRITE_SVLC (pcSlice->getDeblockingFilterBetaOffsetDiv2(), "slice_beta_offset_div2"); + WRITE_SVLC (pcSlice->getDeblockingFilterTcOffsetDiv2(), "slice_tc_offset_div2"); + } + } + } + + Bool isSAOEnabled = pcSlice->getSPS()->getUseSAO() && (pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_LUMA) || (chromaEnabled && pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_CHROMA))); + Bool isDBFEnabled = (!pcSlice->getDeblockingFilterDisable()); + + if(pcSlice->getPPS()->getLoopFilterAcrossSlicesEnabledFlag() && ( isSAOEnabled || isDBFEnabled )) + { + WRITE_FLAG(pcSlice->getLFCrossSliceBoundaryFlag()?1:0, "slice_loop_filter_across_slices_enabled_flag"); + } + } + if(pcSlice->getPPS()->getSliceHeaderExtensionPresentFlag()) + { + WRITE_UVLC(0,"slice_header_extension_length"); + } +} + +Void TEncCavlc::codePTL( TComPTL* pcPTL, Bool profilePresentFlag, Int maxNumSubLayersMinus1) +{ + if(profilePresentFlag) + { + codeProfileTier(pcPTL->getGeneralPTL()); // general_... + } + WRITE_CODE( Int(pcPTL->getGeneralPTL()->getLevelIdc()), 8, "general_level_idc" ); + + for (Int i = 0; i < maxNumSubLayersMinus1; i++) + { + if(profilePresentFlag) + { + WRITE_FLAG( pcPTL->getSubLayerProfilePresentFlag(i), "sub_layer_profile_present_flag[i]" ); + } + + WRITE_FLAG( pcPTL->getSubLayerLevelPresentFlag(i), "sub_layer_level_present_flag[i]" ); + } + + if (maxNumSubLayersMinus1 > 0) + { + for (Int i = maxNumSubLayersMinus1; i < 8; i++) + { + WRITE_CODE(0, 2, "reserved_zero_2bits"); + } + } + + for(Int i = 0; i < maxNumSubLayersMinus1; i++) + { + if( profilePresentFlag && pcPTL->getSubLayerProfilePresentFlag(i) ) + { + codeProfileTier(pcPTL->getSubLayerPTL(i)); // sub_layer_... + } + if( pcPTL->getSubLayerLevelPresentFlag(i) ) + { + WRITE_CODE( Int(pcPTL->getSubLayerPTL(i)->getLevelIdc()), 8, "sub_layer_level_idc[i]" ); + } + } +} +Void TEncCavlc::codeProfileTier( ProfileTierLevel* ptl ) +{ + WRITE_CODE( ptl->getProfileSpace(), 2 , "XXX_profile_space[]"); + WRITE_FLAG( ptl->getTierFlag()==Level::HIGH, "XXX_tier_flag[]" ); + WRITE_CODE( Int(ptl->getProfileIdc()), 5 , "XXX_profile_idc[]" ); + for(Int j = 0; j < 32; j++) + { + WRITE_FLAG( ptl->getProfileCompatibilityFlag(j), "XXX_profile_compatibility_flag[][j]"); + } + + WRITE_FLAG(ptl->getProgressiveSourceFlag(), "general_progressive_source_flag"); + WRITE_FLAG(ptl->getInterlacedSourceFlag(), "general_interlaced_source_flag"); + WRITE_FLAG(ptl->getNonPackedConstraintFlag(), "general_non_packed_constraint_flag"); + WRITE_FLAG(ptl->getFrameOnlyConstraintFlag(), "general_frame_only_constraint_flag"); + + if (ptl->getProfileIdc() == Profile::MAINREXT || ptl->getProfileIdc() == Profile::HIGHTHROUGHPUTREXT ) + { + const UInt bitDepthConstraint=ptl->getBitDepthConstraint(); + WRITE_FLAG(bitDepthConstraint<=12, "general_max_12bit_constraint_flag"); + WRITE_FLAG(bitDepthConstraint<=10, "general_max_10bit_constraint_flag"); + WRITE_FLAG(bitDepthConstraint<= 8, "general_max_8bit_constraint_flag"); + const ChromaFormat chromaFmtConstraint=ptl->getChromaFormatConstraint(); + WRITE_FLAG(chromaFmtConstraint==CHROMA_422||chromaFmtConstraint==CHROMA_420||chromaFmtConstraint==CHROMA_400, "general_max_422chroma_constraint_flag"); + WRITE_FLAG(chromaFmtConstraint==CHROMA_420||chromaFmtConstraint==CHROMA_400, "general_max_420chroma_constraint_flag"); + WRITE_FLAG(chromaFmtConstraint==CHROMA_400, "general_max_monochrome_constraint_flag"); + WRITE_FLAG(ptl->getIntraConstraintFlag(), "general_intra_constraint_flag"); + WRITE_FLAG(0, "general_one_picture_only_constraint_flag"); + WRITE_FLAG(ptl->getLowerBitRateConstraintFlag(), "general_lower_bit_rate_constraint_flag"); + WRITE_CODE(0 , 16, "XXX_reserved_zero_35bits[0..15]"); + WRITE_CODE(0 , 16, "XXX_reserved_zero_35bits[16..31]"); + WRITE_CODE(0 , 3, "XXX_reserved_zero_35bits[32..34]"); + } + else + { + WRITE_CODE(0x0000 , 16, "XXX_reserved_zero_44bits[0..15]"); + WRITE_CODE(0x0000 , 16, "XXX_reserved_zero_44bits[16..31]"); + WRITE_CODE(0x000 , 12, "XXX_reserved_zero_44bits[32..43]"); + } +} + +/** + - write tiles and wavefront substreams sizes for the slice header. + . + \param pcSlice Where we find the substream size information. + */ +Void TEncCavlc::codeTilesWPPEntryPoint( TComSlice* pSlice ) +{ + if (!pSlice->getPPS()->getTilesEnabledFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) + { + return; + } + UInt maxOffset = 0; + for(Int idx=0; idxgetNumberOfSubstreamSizes(); idx++) + { + UInt offset=pSlice->getSubstreamSize(idx); + if ( offset > maxOffset ) + { + maxOffset = offset; + } + } + + // Determine number of bits "offsetLenMinus1+1" required for entry point information + UInt offsetLenMinus1 = 0; + while (maxOffset >= (1u << (offsetLenMinus1 + 1))) + { + offsetLenMinus1++; + assert(offsetLenMinus1 + 1 < 32); + } + + WRITE_UVLC(pSlice->getNumberOfSubstreamSizes(), "num_entry_point_offsets"); + if (pSlice->getNumberOfSubstreamSizes()>0) + { + WRITE_UVLC(offsetLenMinus1, "offset_len_minus1"); + + for (UInt idx=0; idxgetNumberOfSubstreamSizes(); idx++) + { + WRITE_CODE(pSlice->getSubstreamSize(idx)-1, offsetLenMinus1+1, "entry_point_offset_minus1"); + } + } +} + +Void TEncCavlc::codeTerminatingBit ( UInt uilsLast ) +{ +} + +Void TEncCavlc::codeSliceFinish () +{ +} + +Void TEncCavlc::codeMVPIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + assert(0); +} + +Void TEncCavlc::codePartSize( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + assert(0); +} + +Void TEncCavlc::codePredMode( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeMergeFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeMergeIndex ( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeInterModeFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiEncMode ) +{ + assert(0); +} + +Void TEncCavlc::codeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeSkipFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + assert(0); +} + +Void TEncCavlc::codeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ) +{ + assert(0); +} + +Void TEncCavlc::codeQtCbf( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ) +{ + assert(0); +} + +Void TEncCavlc::codeQtRootCbf( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeQtCbfZero( TComTU &rTu, const ChannelType chType ) +{ + assert(0); +} +Void TEncCavlc::codeQtRootCbfZero( TComDataCU* pcCU ) +{ + assert(0); +} + +Void TEncCavlc::codeTransformSkipFlags (TComTU &rTu, ComponentID component ) +{ + assert(0); +} + +/** Code I_PCM information. + * \param pcCU pointer to CU + * \param uiAbsPartIdx CU index + * \returns Void + */ +Void TEncCavlc::codeIPCMInfo( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeIntraDirLumaAng( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool isMultiple) +{ + assert(0); +} + +Void TEncCavlc::codeIntraDirChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeInterDir( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeRefFrmIdx( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + assert(0); +} + +Void TEncCavlc::codeMvd( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + assert(0); +} + +Void TEncCavlc::codeCrossComponentPrediction( TComTU& /*rTu*/, ComponentID /*compID*/ ) +{ + assert(0); +} + +Void TEncCavlc::codeDeltaQP( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + Int iDQp = pcCU->getQP( uiAbsPartIdx ) - pcCU->getRefQP( uiAbsPartIdx ); + + Int qpBdOffsetY = pcCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA); + iDQp = (iDQp + 78 + qpBdOffsetY + (qpBdOffsetY/2)) % (52 + qpBdOffsetY) - 26 - (qpBdOffsetY/2); + + xWriteSvlc( iDQp ); + + return; +} + +Void TEncCavlc::codeChromaQpAdjustment( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + assert(0); +} + +Void TEncCavlc::codeCoeffNxN ( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID ) +{ + assert(0); +} + +Void TEncCavlc::estBit( estBitsSbacStruct* pcEstBitsCabac, Int width, Int height, ChannelType chType ) +{ + // printf("error : no VLC mode support in this version\n"); + return; +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + +/** code explicit wp tables + * \param TComSlice* pcSlice + * \returns Void + */ +Void TEncCavlc::xCodePredWeightTable( TComSlice* pcSlice ) +{ + WPScalingParam *wp; + const ChromaFormat format = pcSlice->getPic()->getChromaFormat(); + const UInt numberValidComponents = getNumberValidComponents(format); + const Bool bChroma = isChromaEnabled(format); + const Int iNbRef = (pcSlice->getSliceType() == B_SLICE ) ? (2) : (1); + Bool bDenomCoded = false; + UInt uiMode = 0; + UInt uiTotalSignalledWeightFlags = 0; + + if ( (pcSlice->getSliceType()==P_SLICE && pcSlice->getPPS()->getUseWP()) || (pcSlice->getSliceType()==B_SLICE && pcSlice->getPPS()->getWPBiPred()) ) + { + uiMode = 1; // explicit + } + if(uiMode == 1) + { + for ( Int iNumRef=0 ; iNumRefgetNumRefIdx(eRefPicList) ; iRefIdx++ ) + { + pcSlice->getWpScaling(eRefPicList, iRefIdx, wp); + if ( !bDenomCoded ) + { + Int iDeltaDenom; + WRITE_UVLC( wp[COMPONENT_Y].uiLog2WeightDenom, "luma_log2_weight_denom" ); // ue(v): luma_log2_weight_denom + + if( bChroma ) + { + assert(wp[COMPONENT_Cb].uiLog2WeightDenom == wp[COMPONENT_Cr].uiLog2WeightDenom); // check the channel-type settings are consistent across components. + iDeltaDenom = (wp[COMPONENT_Cb].uiLog2WeightDenom - wp[COMPONENT_Y].uiLog2WeightDenom); + WRITE_SVLC( iDeltaDenom, "delta_chroma_log2_weight_denom" ); // se(v): delta_chroma_log2_weight_denom + } + bDenomCoded = true; + } + WRITE_FLAG( wp[COMPONENT_Y].bPresentFlag, "luma_weight_lX_flag" ); // u(1): luma_weight_lX_flag + uiTotalSignalledWeightFlags += wp[COMPONENT_Y].bPresentFlag; + } + if (bChroma) + { + for ( Int iRefIdx=0 ; iRefIdxgetNumRefIdx(eRefPicList) ; iRefIdx++ ) + { + pcSlice->getWpScaling(eRefPicList, iRefIdx, wp); + assert(wp[COMPONENT_Cb].bPresentFlag == wp[COMPONENT_Cr].bPresentFlag); // check the channel-type settings are consistent across components. + WRITE_FLAG( wp[COMPONENT_Cb].bPresentFlag, "chroma_weight_lX_flag" ); // u(1): chroma_weight_lX_flag + uiTotalSignalledWeightFlags += 2*wp[COMPONENT_Cb].bPresentFlag; + } + } + + for ( Int iRefIdx=0 ; iRefIdxgetNumRefIdx(eRefPicList) ; iRefIdx++ ) + { + pcSlice->getWpScaling(eRefPicList, iRefIdx, wp); + if ( wp[COMPONENT_Y].bPresentFlag ) + { + Int iDeltaWeight = (wp[COMPONENT_Y].iWeight - (1<getSPS()->getUseHighPrecisionPredictionWeighting() ? (1<>(wp[j].uiLog2WeightDenom) ) ); + Int iDeltaChroma = (wp[j].iOffset - pred); + WRITE_SVLC( iDeltaChroma, "delta_chroma_offset_lX" ); // se(v): delta_chroma_offset_lX + } + } + } + } + } + assert(uiTotalSignalledWeightFlags<=24); + } +} + +/** code quantization matrix + * \param scalingList quantization matrix information + */ +Void TEncCavlc::codeScalingList( TComScalingList* scalingList ) +{ + UInt listId,sizeId; + Bool scalingListPredModeFlag; + + //for each size + for(sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) + { + Int predListStep = (sizeId == SCALING_LIST_32x32? (SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) : 1); // if 32x32, skip over chroma entries. + + for(listId = 0; listId < SCALING_LIST_NUM; listId+=predListStep) + { + scalingListPredModeFlag = scalingList->checkPredMode( sizeId, listId ); + WRITE_FLAG( scalingListPredModeFlag, "scaling_list_pred_mode_flag" ); + if(!scalingListPredModeFlag)// Copy Mode + { + if (sizeId == SCALING_LIST_32x32) + { + // adjust the code, to cope with the missing chroma entries + WRITE_UVLC( ((Int)listId - (Int)scalingList->getRefMatrixId (sizeId,listId)) / (SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES), "scaling_list_pred_matrix_id_delta"); + } + else + { + WRITE_UVLC( (Int)listId - (Int)scalingList->getRefMatrixId (sizeId,listId), "scaling_list_pred_matrix_id_delta"); + } + } + else// DPCM Mode + { + xCodeScalingList(scalingList, sizeId, listId); + } + } + } + return; +} +/** code DPCM + * \param scalingList quantization matrix information + * \param sizeIdc size index + * \param listIdc list index + */ +Void TEncCavlc::xCodeScalingList(TComScalingList* scalingList, UInt sizeId, UInt listId) +{ + Int coefNum = min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId]); + UInt* scan = g_scanOrder[SCAN_UNGROUPED][SCAN_DIAG][sizeId==0 ? 2 : 3][sizeId==0 ? 2 : 3]; + Int nextCoef = SCALING_LIST_START_VALUE; + Int data; + Int *src = scalingList->getScalingListAddress(sizeId, listId); + if( sizeId > SCALING_LIST_8x8 ) + { + WRITE_SVLC( scalingList->getScalingListDC(sizeId,listId) - 8, "scaling_list_dc_coef_minus8"); + nextCoef = scalingList->getScalingListDC(sizeId,listId); + } + for(Int i=0;i 127) + { + data = data - 256; + } + if(data < -128) + { + data = data + 256; + } + + WRITE_SVLC( data, "scaling_list_delta_coef"); + } +} +Bool TEncCavlc::findMatchingLTRP ( TComSlice* pcSlice, UInt *ltrpsIndex, Int ltrpPOC, Bool usedFlag ) +{ + // Bool state = true, state2 = false; + Int lsb = ltrpPOC & ((1<getSPS()->getBitsForPOC())-1); + for (Int k = 0; k < pcSlice->getSPS()->getNumLongTermRefPicSPS(); k++) + { + if ( (lsb == pcSlice->getSPS()->getLtRefPicPocLsbSps(k)) && (usedFlag == pcSlice->getSPS()->getUsedByCurrPicLtSPSFlag(k)) ) + { + *ltrpsIndex = k; + return true; + } + } + return false; +} +Bool TComScalingList::checkPredMode(UInt sizeId, UInt listId) +{ + Int predListStep = (sizeId == SCALING_LIST_32x32? (SCALING_LIST_NUM/NUMBER_OF_PREDICTION_MODES) : 1); // if 32x32, skip over chroma entries. + + for(Int predListIdx = (Int)listId ; predListIdx >= 0; predListIdx-=predListStep) + { + if( !memcmp(getScalingListAddress(sizeId,listId),((listId == predListIdx) ? + getScalingListDefaultAddress(sizeId, predListIdx): getScalingListAddress(sizeId, predListIdx)),sizeof(Int)*min(MAX_MATRIX_COEF_NUM,(Int)g_scalingListSize[sizeId])) // check value of matrix + && ((sizeId < SCALING_LIST_16x16) || (getScalingListDC(sizeId,listId) == getScalingListDC(sizeId,predListIdx)))) // check DC value + { + setRefMatrixId(sizeId, listId, predListIdx); + return false; + } + } + return true; +} + +Void TEncCavlc::codeExplicitRdpcmMode( TComTU &rTu, const ComponentID compID ) + { + assert(0); + } + +//! \} diff --git a/jctvc/TLibEncoder/TEncCavlc.h b/jctvc/TLibEncoder/TEncCavlc.h new file mode 100644 index 0000000..be2e275 --- /dev/null +++ b/jctvc/TLibEncoder/TEncCavlc.h @@ -0,0 +1,144 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncCavlc.h + \brief CAVLC encoder class (header) +*/ + +#ifndef __TENCCAVLC__ +#define __TENCCAVLC__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/TComRom.h" +#include "TEncEntropy.h" +#include "SyntaxElementWriter.h" + +//! \ingroup TLibEncoder +//! \{ + +class TEncTop; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// CAVLC encoder class +class TEncCavlc : public SyntaxElementWriter, public TEncEntropyIf +{ +public: + TEncCavlc(); + virtual ~TEncCavlc(); + +protected: + TComSlice* m_pcSlice; + + Void codeShortTermRefPicSet ( TComSPS* pcSPS, TComReferencePictureSet* pcRPS, Bool calledFromSliceHeader, Int idx ); + Bool findMatchingLTRP ( TComSlice* pcSlice, UInt *ltrpsIndex, Int ltrpPOC, Bool usedFlag ); + +public: + + Void resetEntropy (); + Void determineCabacInitIdx () {}; + + Void setBitstream ( TComBitIf* p ) { m_pcBitIf = p; } + Void setSlice ( TComSlice* p ) { m_pcSlice = p; } + Void resetBits () { m_pcBitIf->resetBits(); } + UInt getNumberOfWrittenBits() { return m_pcBitIf->getNumberOfWrittenBits(); } + Void codeVPS ( TComVPS* pcVPS ); + Void codeVUI ( TComVUI *pcVUI, TComSPS* pcSPS ); + Void codeSPS ( TComSPS* pcSPS ); + Void codePPS ( TComPPS* pcPPS ); + Void codeSliceHeader ( TComSlice* pcSlice ); + Void codePTL ( TComPTL* pcPTL, Bool profilePresentFlag, Int maxNumSubLayersMinus1); + Void codeProfileTier ( ProfileTierLevel* ptl ); + Void codeHrdParameters ( TComHRD *hrd, Bool commonInfPresentFlag, UInt maxNumSubLayersMinus1 ); + Void codeTilesWPPEntryPoint( TComSlice* pSlice ); + Void codeTerminatingBit ( UInt uilsLast ); + Void codeSliceFinish (); + + Void codeMVPIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ); + Void codeSAOBlkParam(SAOBlkParam& saoBlkParam, Bool* sliceEnabled, Bool leftMergeAvail, Bool aboveMergeAvail, Bool onlyEstMergeInfo = false){printf("only supported in CABAC"); assert(0); exit(-1);} + Void codeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeSkipFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeMergeFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeMergeIndex ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + + Void codeAlfCtrlFlag ( ComponentID component, UInt code ) {printf("Not supported\n"); assert(0);} + Void codeInterModeFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiEncMode ); + Void codeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ); + + Void codePartSize ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ); + Void codePredMode ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + + Void codeIPCMInfo ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + + Void codeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ); + Void codeQtCbf ( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ); + Void codeQtRootCbf ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeQtCbfZero ( TComTU &rTu, const ChannelType chType ); + Void codeQtRootCbfZero ( TComDataCU* pcCU ); + Void codeIntraDirLumaAng( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiple); + Void codeIntraDirChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeInterDir ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeRefFrmIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ); + Void codeMvd ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ); + + Void codeCrossComponentPrediction( TComTU &rTu, ComponentID compID ); + + Void codeDeltaQP ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void codeChromaQpAdjustment( TComDataCU* pcCU, UInt uiAbsPartIdx ); + + Void codeCoeffNxN ( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID ); + Void codeTransformSkipFlags ( TComTU &rTu, ComponentID component ); + + Void estBit ( estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType ); + + Void xCodePredWeightTable ( TComSlice* pcSlice ); + + Void codeScalingList ( TComScalingList* scalingList ); + Void xCodeScalingList ( TComScalingList* scalingList, UInt sizeId, UInt listId); + Void codeDFFlag ( UInt uiCode, const Char *pSymbolName ); + Void codeDFSvlc ( Int iCode, const Char *pSymbolName ); + + Void codeExplicitRdpcmMode( TComTU &rTu, const ComponentID compID ); +}; + +//! \} + +#endif // !defined(AFX_TENCCAVLC_H__EE8A0B30_945B_4169_B290_24D3AD52296F__INCLUDED_) + diff --git a/jctvc/TLibEncoder/TEncCfg.h b/jctvc/TLibEncoder/TEncCfg.h new file mode 100644 index 0000000..ee2ace5 --- /dev/null +++ b/jctvc/TLibEncoder/TEncCfg.h @@ -0,0 +1,879 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncCfg.h + \brief encoder configuration class (header) +*/ + +#ifndef __TENCCFG__ +#define __TENCCFG__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComSlice.h" +#include + +struct GOPEntry +{ + Int m_POC; + Int m_QPOffset; + Double m_QPFactor; + Int m_tcOffsetDiv2; + Int m_betaOffsetDiv2; + Int m_temporalId; + Bool m_refPic; + Int m_numRefPicsActive; + Char m_sliceType; + Int m_numRefPics; + Int m_referencePics[MAX_NUM_REF_PICS]; + Int m_usedByCurrPic[MAX_NUM_REF_PICS]; +#if AUTO_INTER_RPS + Int m_interRPSPrediction; +#else + Bool m_interRPSPrediction; +#endif + Int m_deltaRPS; + Int m_numRefIdc; + Int m_refIdc[MAX_NUM_REF_PICS+1]; + Bool m_isEncoded; + GOPEntry() + : m_POC(-1) + , m_QPOffset(0) + , m_QPFactor(0) + , m_tcOffsetDiv2(0) + , m_betaOffsetDiv2(0) + , m_temporalId(0) + , m_refPic(false) + , m_numRefPicsActive(0) + , m_sliceType('P') + , m_numRefPics(0) + , m_interRPSPrediction(false) + , m_deltaRPS(0) + , m_numRefIdc(0) + , m_isEncoded(false) + { + ::memset( m_referencePics, 0, sizeof(m_referencePics) ); + ::memset( m_usedByCurrPic, 0, sizeof(m_usedByCurrPic) ); + ::memset( m_refIdc, 0, sizeof(m_refIdc) ); + } +}; + +std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry); //input +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// encoder configuration class +class TEncCfg +{ +protected: + //==== File I/O ======== + Int m_iFrameRate; + Int m_FrameSkip; + Int m_iSourceWidth; + Int m_iSourceHeight; + Window m_conformanceWindow; + Int m_framesToBeEncoded; + Double m_adLambdaModifier[ MAX_TLAYER ]; + + Bool m_printMSEBasedSequencePSNR; + Bool m_printFrameMSE; + Bool m_printSequenceMSE; + Bool m_cabacZeroWordPaddingEnabled; + + /* profile & level */ + Profile::Name m_profile; + Level::Tier m_levelTier; + Level::Name m_level; + Bool m_progressiveSourceFlag; + Bool m_interlacedSourceFlag; + Bool m_nonPackedConstraintFlag; + Bool m_frameOnlyConstraintFlag; + UInt m_bitDepthConstraintValue; + ChromaFormat m_chromaFormatConstraintValue; + Bool m_intraConstraintFlag; + Bool m_lowerBitRateConstraintFlag; + + //====== Coding Structure ======== + UInt m_uiIntraPeriod; + UInt m_uiDecodingRefreshType; ///< the type of decoding refresh employed for the random access. + Int m_iGOPSize; + GOPEntry m_GOPList[MAX_GOP]; + Int m_extraRPSs; + Int m_maxDecPicBuffering[MAX_TLAYER]; + Int m_numReorderPics[MAX_TLAYER]; + + Int m_iQP; // if (AdaptiveQP == OFF) + + Int m_aiPad[2]; + + + Int m_iMaxRefPicNum; ///< this is used to mimic the sliding mechanism used by the decoder + // TODO: We need to have a common sliding mechanism used by both the encoder and decoder + + Int m_maxTempLayer; ///< Max temporal layer + Bool m_useAMP; + //======= Transform ============= + UInt m_uiQuadtreeTULog2MaxSize; + UInt m_uiQuadtreeTULog2MinSize; + UInt m_uiQuadtreeTUMaxDepthInter; + UInt m_uiQuadtreeTUMaxDepthIntra; + + //====== Loop/Deblock Filter ======== + Bool m_bLoopFilterDisable; + Bool m_loopFilterOffsetInPPS; + Int m_loopFilterBetaOffsetDiv2; + Int m_loopFilterTcOffsetDiv2; + Bool m_DeblockingFilterControlPresent; + Bool m_DeblockingFilterMetric; + Bool m_bUseSAO; + Int m_maxNumOffsetsPerPic; + Bool m_saoCtuBoundary; + + //====== Motion search ======== + Int m_iFastSearch; // 0:Full search 1:Diamond 2:PMVFAST + Int m_iSearchRange; // 0:Full frame + Int m_bipredSearchRange; + + //====== Quality control ======== + Int m_iMaxDeltaQP; // Max. absolute delta QP (1:default) + Int m_iMaxCuDQPDepth; // Max. depth for a minimum CuDQP (0:default) + Int m_maxCUChromaQpAdjustmentDepth; + + Int m_chromaCbQpOffset; // Chroma Cb QP Offset (0:default) + Int m_chromaCrQpOffset; // Chroma Cr Qp Offset (0:default) + ChromaFormat m_chromaFormatIDC; + +#if ADAPTIVE_QP_SELECTION + Bool m_bUseAdaptQpSelect; +#endif + Bool m_useExtendedPrecision; + Bool m_useHighPrecisionPredictionWeighting; + Bool m_bUseAdaptiveQP; + Int m_iQPAdaptationRange; + + //====== Tool list ======== + Bool m_bUseASR; + Bool m_bUseHADME; + Bool m_useRDOQ; + Bool m_useRDOQTS; + UInt m_rdPenalty; + Bool m_bUseFastEnc; + Bool m_bUseEarlyCU; + Bool m_useFastDecisionForMerge; + Bool m_bUseCbfFastMode; + Bool m_useEarlySkipDetection; + Bool m_useCrossComponentPrediction; + Bool m_reconBasedCrossCPredictionEstimate; + UInt m_saoOffsetBitShift[MAX_NUM_CHANNEL_TYPE]; + Bool m_useTransformSkip; + Bool m_useTransformSkipFast; + UInt m_transformSkipLog2MaxSize; + Bool m_useResidualRotation; + Bool m_useSingleSignificanceMapContext; + Bool m_useGolombRiceParameterAdaptation; + Bool m_alignCABACBeforeBypass; + Bool m_useResidualDPCM[NUMBER_OF_RDPCM_SIGNALLING_MODES]; + Int* m_aidQP; + UInt m_uiDeltaQpRD; + + Bool m_bUseConstrainedIntraPred; + Bool m_usePCM; + UInt m_pcmLog2MaxSize; + UInt m_uiPCMLog2MinSize; + //====== Slice ======== + SliceConstraint m_sliceMode; + Int m_sliceArgument; + //====== Dependent Slice ======== + SliceConstraint m_sliceSegmentMode; + Int m_sliceSegmentArgument; + Bool m_bLFCrossSliceBoundaryFlag; + + Bool m_bPCMInputBitDepthFlag; + UInt m_uiPCMBitDepthLuma; + UInt m_uiPCMBitDepthChroma; + Bool m_bPCMFilterDisableFlag; + Bool m_disableIntraReferenceSmoothing; + Bool m_loopFilterAcrossTilesEnabledFlag; + Bool m_tileUniformSpacingFlag; + Int m_iNumColumnsMinus1; + Int m_iNumRowsMinus1; + std::vector m_tileColumnWidth; + std::vector m_tileRowHeight; + + Int m_iWaveFrontSynchro; + Int m_iWaveFrontSubstreams; + + Int m_decodedPictureHashSEIEnabled; ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message + Int m_bufferingPeriodSEIEnabled; + Int m_pictureTimingSEIEnabled; + Int m_recoveryPointSEIEnabled; + Bool m_toneMappingInfoSEIEnabled; + Int m_toneMapId; + Bool m_toneMapCancelFlag; + Bool m_toneMapPersistenceFlag; + Int m_codedDataBitDepth; + Int m_targetBitDepth; + Int m_modelId; + Int m_minValue; + Int m_maxValue; + Int m_sigmoidMidpoint; + Int m_sigmoidWidth; + Int m_numPivots; + Int m_cameraIsoSpeedIdc; + Int m_cameraIsoSpeedValue; + Int m_exposureIndexIdc; + Int m_exposureIndexValue; + Int m_exposureCompensationValueSignFlag; + Int m_exposureCompensationValueNumerator; + Int m_exposureCompensationValueDenomIdc; + Int m_refScreenLuminanceWhite; + Int m_extendedRangeWhiteLevel; + Int m_nominalBlackLevelLumaCodeValue; + Int m_nominalWhiteLevelLumaCodeValue; + Int m_extendedWhiteLevelLumaCodeValue; + Int* m_startOfCodedInterval; + Int* m_codedPivotValue; + Int* m_targetPivotValue; + Int m_framePackingSEIEnabled; + Int m_framePackingSEIType; + Int m_framePackingSEIId; + Int m_framePackingSEIQuincunx; + Int m_framePackingSEIInterpretation; + Int m_segmentedRectFramePackingSEIEnabled; + Bool m_segmentedRectFramePackingSEICancel; + Int m_segmentedRectFramePackingSEIType; + Bool m_segmentedRectFramePackingSEIPersistence; + Int m_displayOrientationSEIAngle; + Int m_temporalLevel0IndexSEIEnabled; + Int m_gradualDecodingRefreshInfoEnabled; + Int m_noDisplaySEITLayer; + Int m_decodingUnitInfoSEIEnabled; + Int m_SOPDescriptionSEIEnabled; + Int m_scalableNestingSEIEnabled; + Bool m_tmctsSEIEnabled; + Bool m_timeCodeSEIEnabled; + Int m_timeCodeSEINumTs; + TComSEITimeSet m_timeSetArray[MAX_TIMECODE_SEI_SETS]; + Bool m_kneeSEIEnabled; + Int m_kneeSEIId; + Bool m_kneeSEICancelFlag; + Bool m_kneeSEIPersistenceFlag; + Int m_kneeSEIInputDrange; + Int m_kneeSEIInputDispLuminance; + Int m_kneeSEIOutputDrange; + Int m_kneeSEIOutputDispLuminance; + Int m_kneeSEINumKneePointsMinus1; + Int* m_kneeSEIInputKneePoint; + Int* m_kneeSEIOutputKneePoint; + TComSEIMasteringDisplay m_masteringDisplay; + //====== Weighted Prediction ======== + Bool m_useWeightedPred; //< Use of Weighting Prediction (P_SLICE) + Bool m_useWeightedBiPred; //< Use of Bi-directional Weighting Prediction (B_SLICE) + UInt m_log2ParallelMergeLevelMinus2; ///< Parallel merge estimation region + UInt m_maxNumMergeCand; ///< Maximum number of merge candidates + ScalingListMode m_useScalingListId; ///< Using quantization matrix i.e. 0=off, 1=default, 2=file. + Char* m_scalingListFile; ///< quantization matrix file name + Int m_TMVPModeId; + Int m_signHideFlag; + Bool m_RCEnableRateControl; + Int m_RCTargetBitrate; + Int m_RCKeepHierarchicalBit; + Bool m_RCLCULevelRC; + Bool m_RCUseLCUSeparateModel; + Int m_RCInitialQP; + Bool m_RCForceIntraQP; + Bool m_TransquantBypassEnableFlag; ///< transquant_bypass_enable_flag setting in PPS. + Bool m_CUTransquantBypassFlagForce; ///< if transquant_bypass_enable_flag, then, if true, all CU transquant bypass flags will be set to true. + + CostMode m_costMode; ///< The cost function to use, primarily when considering lossless coding. + + TComVPS m_cVPS; + Bool m_recalculateQPAccordingToLambda; ///< recalculate QP value according to the lambda value + Int m_activeParameterSetsSEIEnabled; ///< enable active parameter set SEI message + Bool m_vuiParametersPresentFlag; ///< enable generation of VUI parameters + Bool m_aspectRatioInfoPresentFlag; ///< Signals whether aspect_ratio_idc is present + Bool m_chromaSamplingFilterHintEnabled; ///< Signals whether chroma sampling filter hint data is present + Int m_chromaSamplingHorFilterIdc; ///< Specifies the Index of filter to use + Int m_chromaSamplingVerFilterIdc; ///< Specifies the Index of filter to use + Int m_aspectRatioIdc; ///< aspect_ratio_idc + Int m_sarWidth; ///< horizontal size of the sample aspect ratio + Int m_sarHeight; ///< vertical size of the sample aspect ratio + Bool m_overscanInfoPresentFlag; ///< Signals whether overscan_appropriate_flag is present + Bool m_overscanAppropriateFlag; ///< Indicates whether conformant decoded pictures are suitable for display using overscan + Bool m_videoSignalTypePresentFlag; ///< Signals whether video_format, video_full_range_flag, and colour_description_present_flag are present + Int m_videoFormat; ///< Indicates representation of pictures + Bool m_videoFullRangeFlag; ///< Indicates the black level and range of luma and chroma signals + Bool m_colourDescriptionPresentFlag; ///< Signals whether colour_primaries, transfer_characteristics and matrix_coefficients are present + Int m_colourPrimaries; ///< Indicates chromaticity coordinates of the source primaries + Int m_transferCharacteristics; ///< Indicates the opto-electronic transfer characteristics of the source + Int m_matrixCoefficients; ///< Describes the matrix coefficients used in deriving luma and chroma from RGB primaries + Bool m_chromaLocInfoPresentFlag; ///< Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present + Int m_chromaSampleLocTypeTopField; ///< Specifies the location of chroma samples for top field + Int m_chromaSampleLocTypeBottomField; ///< Specifies the location of chroma samples for bottom field + Bool m_neutralChromaIndicationFlag; ///< Indicates that the value of all decoded chroma samples is equal to 1<<(BitDepthCr-1) + Window m_defaultDisplayWindow; ///< Represents the default display window parameters + Bool m_frameFieldInfoPresentFlag; ///< Indicates that pic_struct and other field coding related values are present in picture timing SEI messages + Bool m_pocProportionalToTimingFlag; ///< Indicates that the POC value is proportional to the output time w.r.t. first picture in CVS + Int m_numTicksPocDiffOneMinus1; ///< Number of ticks minus 1 that for a POC difference of one + Bool m_bitstreamRestrictionFlag; ///< Signals whether bitstream restriction parameters are present + Bool m_tilesFixedStructureFlag; ///< Indicates that each active picture parameter set has the same values of the syntax elements related to tiles + Bool m_motionVectorsOverPicBoundariesFlag; ///< Indicates that no samples outside the picture boundaries are used for inter prediction + Int m_minSpatialSegmentationIdc; ///< Indicates the maximum size of the spatial segments in the pictures in the coded video sequence + Int m_maxBytesPerPicDenom; ///< Indicates a number of bytes not exceeded by the sum of the sizes of the VCL NAL units associated with any coded picture + Int m_maxBitsPerMinCuDenom; ///< Indicates an upper bound for the number of bits of coding_unit() data + Int m_log2MaxMvLengthHorizontal; ///< Indicate the maximum absolute value of a decoded horizontal MV component in quarter-pel luma units + Int m_log2MaxMvLengthVertical; ///< Indicate the maximum absolute value of a decoded vertical MV component in quarter-pel luma units + + Bool m_useStrongIntraSmoothing; ///< enable the use of strong intra smoothing (bi_linear interpolation) for 32x32 blocks when reference samples are flat. + +public: + TEncCfg() + : m_tileColumnWidth() + , m_tileRowHeight() + {} + + virtual ~TEncCfg() + {} + + Void setProfile(Profile::Name profile) { m_profile = profile; } + Void setLevel(Level::Tier tier, Level::Name level) { m_levelTier = tier; m_level = level; } + + Void setFrameRate ( Int i ) { m_iFrameRate = i; } + Void setFrameSkip ( UInt i ) { m_FrameSkip = i; } + Void setSourceWidth ( Int i ) { m_iSourceWidth = i; } + Void setSourceHeight ( Int i ) { m_iSourceHeight = i; } + + Window &getConformanceWindow() { return m_conformanceWindow; } + Void setConformanceWindow (Int confLeft, Int confRight, Int confTop, Int confBottom ) { m_conformanceWindow.setWindow (confLeft, confRight, confTop, confBottom); } + + Void setFramesToBeEncoded ( Int i ) { m_framesToBeEncoded = i; } + + Bool getPrintMSEBasedSequencePSNR () const { return m_printMSEBasedSequencePSNR; } + Void setPrintMSEBasedSequencePSNR (Bool value) { m_printMSEBasedSequencePSNR = value; } + + Bool getPrintFrameMSE () const { return m_printFrameMSE; } + Void setPrintFrameMSE (Bool value) { m_printFrameMSE = value; } + + Bool getPrintSequenceMSE () const { return m_printSequenceMSE; } + Void setPrintSequenceMSE (Bool value) { m_printSequenceMSE = value; } + + Bool getCabacZeroWordPaddingEnabled() const { return m_cabacZeroWordPaddingEnabled; } + Void setCabacZeroWordPaddingEnabled(Bool value) { m_cabacZeroWordPaddingEnabled = value; } + + //====== Coding Structure ======== + Void setIntraPeriod ( Int i ) { m_uiIntraPeriod = (UInt)i; } + Void setDecodingRefreshType ( Int i ) { m_uiDecodingRefreshType = (UInt)i; } + Void setGOPSize ( Int i ) { m_iGOPSize = i; } + Void setGopList ( GOPEntry* GOPList ) { for ( Int i = 0; i < MAX_GOP; i++ ) m_GOPList[i] = GOPList[i]; } + Void setExtraRPSs ( Int i ) { m_extraRPSs = i; } + GOPEntry getGOPEntry ( Int i ) { return m_GOPList[i]; } + Void setEncodedFlag ( Int i, Bool value ) { m_GOPList[i].m_isEncoded = value; } + Void setMaxDecPicBuffering ( UInt u, UInt tlayer ) { m_maxDecPicBuffering[tlayer] = u; } + Void setNumReorderPics ( Int i, UInt tlayer ) { m_numReorderPics[tlayer] = i; } + + Void setQP ( Int i ) { m_iQP = i; } + + Void setPad ( Int* iPad ) { for ( Int i = 0; i < 2; i++ ) m_aiPad[i] = iPad[i]; } + + Int getMaxRefPicNum () { return m_iMaxRefPicNum; } + Void setMaxRefPicNum ( Int iMaxRefPicNum ) { m_iMaxRefPicNum = iMaxRefPicNum; } + + Int getMaxTempLayer () { return m_maxTempLayer; } + Void setMaxTempLayer ( Int maxTempLayer ) { m_maxTempLayer = maxTempLayer; } + //======== Transform ============= + Void setQuadtreeTULog2MaxSize ( UInt u ) { m_uiQuadtreeTULog2MaxSize = u; } + Void setQuadtreeTULog2MinSize ( UInt u ) { m_uiQuadtreeTULog2MinSize = u; } + Void setQuadtreeTUMaxDepthInter ( UInt u ) { m_uiQuadtreeTUMaxDepthInter = u; } + Void setQuadtreeTUMaxDepthIntra ( UInt u ) { m_uiQuadtreeTUMaxDepthIntra = u; } + + Void setUseAMP( Bool b ) { m_useAMP = b; } + + //====== Loop/Deblock Filter ======== + Void setLoopFilterDisable ( Bool b ) { m_bLoopFilterDisable = b; } + Void setLoopFilterOffsetInPPS ( Bool b ) { m_loopFilterOffsetInPPS = b; } + Void setLoopFilterBetaOffset ( Int i ) { m_loopFilterBetaOffsetDiv2 = i; } + Void setLoopFilterTcOffset ( Int i ) { m_loopFilterTcOffsetDiv2 = i; } + Void setDeblockingFilterControlPresent ( Bool b ) { m_DeblockingFilterControlPresent = b; } + Void setDeblockingFilterMetric ( Bool b ) { m_DeblockingFilterMetric = b; } + + //====== Motion search ======== + Void setFastSearch ( Int i ) { m_iFastSearch = i; } + Void setSearchRange ( Int i ) { m_iSearchRange = i; } + Void setBipredSearchRange ( Int i ) { m_bipredSearchRange = i; } + + //====== Quality control ======== + Void setMaxDeltaQP ( Int i ) { m_iMaxDeltaQP = i; } + Void setMaxCuDQPDepth ( Int i ) { m_iMaxCuDQPDepth = i; } + + Int getMaxCUChromaQpAdjustmentDepth () const { return m_maxCUChromaQpAdjustmentDepth; } + Void setMaxCUChromaQpAdjustmentDepth (Int value) { m_maxCUChromaQpAdjustmentDepth = value; } + + Void setChromaCbQpOffset ( Int i ) { m_chromaCbQpOffset = i; } + Void setChromaCrQpOffset ( Int i ) { m_chromaCrQpOffset = i; } + + Void setChromaFormatIdc ( ChromaFormat cf ) { m_chromaFormatIDC = cf; } + ChromaFormat getChromaFormatIdc ( ) { return m_chromaFormatIDC; } + +#if ADAPTIVE_QP_SELECTION + Void setUseAdaptQpSelect ( Bool i ) { m_bUseAdaptQpSelect = i; } + Bool getUseAdaptQpSelect () { return m_bUseAdaptQpSelect; } +#endif + + Bool getUseExtendedPrecision () const { return m_useExtendedPrecision; } + Void setUseExtendedPrecision (Bool value) { m_useExtendedPrecision = value; } + + Bool getUseHighPrecisionPredictionWeighting() const { return m_useHighPrecisionPredictionWeighting; } + Void setUseHighPrecisionPredictionWeighting(Bool value) { m_useHighPrecisionPredictionWeighting = value; } + + Void setUseAdaptiveQP ( Bool b ) { m_bUseAdaptiveQP = b; } + Void setQPAdaptationRange ( Int i ) { m_iQPAdaptationRange = i; } + + //====== Sequence ======== + Int getFrameRate () { return m_iFrameRate; } + UInt getFrameSkip () { return m_FrameSkip; } + Int getSourceWidth () { return m_iSourceWidth; } + Int getSourceHeight () { return m_iSourceHeight; } + Int getFramesToBeEncoded () { return m_framesToBeEncoded; } + Void setLambdaModifier ( UInt uiIndex, Double dValue ) { m_adLambdaModifier[ uiIndex ] = dValue; } + Double getLambdaModifier ( UInt uiIndex ) const { return m_adLambdaModifier[ uiIndex ]; } + + //==== Coding Structure ======== + UInt getIntraPeriod () { return m_uiIntraPeriod; } + UInt getDecodingRefreshType () { return m_uiDecodingRefreshType; } + Int getGOPSize () { return m_iGOPSize; } + Int getMaxDecPicBuffering (UInt tlayer) { return m_maxDecPicBuffering[tlayer]; } + Int getNumReorderPics (UInt tlayer) { return m_numReorderPics[tlayer]; } + Int getQP () { return m_iQP; } + + Int getPad ( Int i ) { assert (i < 2 ); return m_aiPad[i]; } + + //======== Transform ============= + UInt getQuadtreeTULog2MaxSize () const { return m_uiQuadtreeTULog2MaxSize; } + UInt getQuadtreeTULog2MinSize () const { return m_uiQuadtreeTULog2MinSize; } + UInt getQuadtreeTUMaxDepthInter () const { return m_uiQuadtreeTUMaxDepthInter; } + UInt getQuadtreeTUMaxDepthIntra () const { return m_uiQuadtreeTUMaxDepthIntra; } + + //==== Loop/Deblock Filter ======== + Bool getLoopFilterDisable () { return m_bLoopFilterDisable; } + Bool getLoopFilterOffsetInPPS () { return m_loopFilterOffsetInPPS; } + Int getLoopFilterBetaOffset () { return m_loopFilterBetaOffsetDiv2; } + Int getLoopFilterTcOffset () { return m_loopFilterTcOffsetDiv2; } + Bool getDeblockingFilterControlPresent() { return m_DeblockingFilterControlPresent; } + Bool getDeblockingFilterMetric () { return m_DeblockingFilterMetric; } + + //==== Motion search ======== + Int getFastSearch () { return m_iFastSearch; } + Int getSearchRange () { return m_iSearchRange; } + + //==== Quality control ======== + Int getMaxDeltaQP () { return m_iMaxDeltaQP; } + Int getMaxCuDQPDepth () { return m_iMaxCuDQPDepth; } + Bool getUseAdaptiveQP () { return m_bUseAdaptiveQP; } + Int getQPAdaptationRange () { return m_iQPAdaptationRange; } + + //==== Tool list ======== + Void setUseASR ( Bool b ) { m_bUseASR = b; } + Void setUseHADME ( Bool b ) { m_bUseHADME = b; } + Void setUseRDOQ ( Bool b ) { m_useRDOQ = b; } + Void setUseRDOQTS ( Bool b ) { m_useRDOQTS = b; } + Void setRDpenalty ( UInt b ) { m_rdPenalty = b; } + Void setUseFastEnc ( Bool b ) { m_bUseFastEnc = b; } + Void setUseEarlyCU ( Bool b ) { m_bUseEarlyCU = b; } + Void setUseFastDecisionForMerge ( Bool b ) { m_useFastDecisionForMerge = b; } + Void setUseCbfFastMode ( Bool b ) { m_bUseCbfFastMode = b; } + Void setUseEarlySkipDetection ( Bool b ) { m_useEarlySkipDetection = b; } + Void setUseConstrainedIntraPred ( Bool b ) { m_bUseConstrainedIntraPred = b; } + Void setPCMInputBitDepthFlag ( Bool b ) { m_bPCMInputBitDepthFlag = b; } + Void setPCMFilterDisableFlag ( Bool b ) { m_bPCMFilterDisableFlag = b; } + Void setUsePCM ( Bool b ) { m_usePCM = b; } + Void setPCMLog2MaxSize ( UInt u ) { m_pcmLog2MaxSize = u; } + Void setPCMLog2MinSize ( UInt u ) { m_uiPCMLog2MinSize = u; } + Void setdQPs ( Int* p ) { m_aidQP = p; } + Void setDeltaQpRD ( UInt u ) {m_uiDeltaQpRD = u; } + Bool getUseASR () { return m_bUseASR; } + Bool getUseHADME () { return m_bUseHADME; } + Bool getUseRDOQ () { return m_useRDOQ; } + Bool getUseRDOQTS () { return m_useRDOQTS; } + Int getRDpenalty () { return m_rdPenalty; } + Bool getUseFastEnc () { return m_bUseFastEnc; } + Bool getUseEarlyCU () { return m_bUseEarlyCU; } + Bool getUseFastDecisionForMerge () { return m_useFastDecisionForMerge; } + Bool getUseCbfFastMode () { return m_bUseCbfFastMode; } + Bool getUseEarlySkipDetection () { return m_useEarlySkipDetection; } + Bool getUseConstrainedIntraPred () { return m_bUseConstrainedIntraPred; } + Bool getPCMInputBitDepthFlag () { return m_bPCMInputBitDepthFlag; } + Bool getPCMFilterDisableFlag () { return m_bPCMFilterDisableFlag; } + Bool getUsePCM () { return m_usePCM; } + UInt getPCMLog2MaxSize () { return m_pcmLog2MaxSize; } + UInt getPCMLog2MinSize () { return m_uiPCMLog2MinSize; } + + Bool getUseCrossComponentPrediction () const { return m_useCrossComponentPrediction; } + Void setUseCrossComponentPrediction (const Bool value) { m_useCrossComponentPrediction = value; } + Bool getUseReconBasedCrossCPredictionEstimate () const { return m_reconBasedCrossCPredictionEstimate; } + Void setUseReconBasedCrossCPredictionEstimate (const Bool value) { m_reconBasedCrossCPredictionEstimate = value; } + Void setSaoOffsetBitShift(ChannelType type, UInt uiBitShift) { m_saoOffsetBitShift[type] = uiBitShift; } + + Bool getUseTransformSkip () { return m_useTransformSkip; } + Void setUseTransformSkip ( Bool b ) { m_useTransformSkip = b; } + Bool getUseResidualRotation () const { return m_useResidualRotation; } + Void setUseResidualRotation (const Bool value) { m_useResidualRotation = value; } + Bool getUseSingleSignificanceMapContext () const { return m_useSingleSignificanceMapContext; } + Void setUseSingleSignificanceMapContext (const Bool value) { m_useSingleSignificanceMapContext = value; } + Bool getUseGolombRiceParameterAdaptation () const { return m_useGolombRiceParameterAdaptation; } + Void setUseGolombRiceParameterAdaptation (const Bool value) { m_useGolombRiceParameterAdaptation = value; } + Bool getAlignCABACBeforeBypass () const { return m_alignCABACBeforeBypass; } + Void setAlignCABACBeforeBypass (const Bool value) { m_alignCABACBeforeBypass = value; } + Bool getUseResidualDPCM (const RDPCMSignallingMode signallingMode) const { return m_useResidualDPCM[signallingMode]; } + Void setUseResidualDPCM (const RDPCMSignallingMode signallingMode, const Bool value) { m_useResidualDPCM[signallingMode] = value; } + Bool getUseTransformSkipFast () { return m_useTransformSkipFast; } + Void setUseTransformSkipFast ( Bool b ) { m_useTransformSkipFast = b; } + UInt getTransformSkipLog2MaxSize () const { return m_transformSkipLog2MaxSize; } + Void setTransformSkipLog2MaxSize ( UInt u ) { m_transformSkipLog2MaxSize = u; } + Void setDisableIntraReferenceSmoothing (Bool bValue) { m_disableIntraReferenceSmoothing=bValue; } + Bool getDisableIntraReferenceSmoothing () const { return m_disableIntraReferenceSmoothing; } + + Int* getdQPs () { return m_aidQP; } + UInt getDeltaQpRD () { return m_uiDeltaQpRD; } + + //====== Slice ======== + Void setSliceMode ( SliceConstraint i ) { m_sliceMode = i; } + Void setSliceArgument ( Int i ) { m_sliceArgument = i; } + SliceConstraint getSliceMode () const { return m_sliceMode; } + Int getSliceArgument () { return m_sliceArgument; } + //====== Dependent Slice ======== + Void setSliceSegmentMode ( SliceConstraint i ) { m_sliceSegmentMode = i; } + Void setSliceSegmentArgument ( Int i ) { m_sliceSegmentArgument = i; } + SliceConstraint getSliceSegmentMode () const { return m_sliceSegmentMode; } + Int getSliceSegmentArgument () { return m_sliceSegmentArgument;} + Void setLFCrossSliceBoundaryFlag ( Bool bValue ) { m_bLFCrossSliceBoundaryFlag = bValue; } + Bool getLFCrossSliceBoundaryFlag () { return m_bLFCrossSliceBoundaryFlag; } + + Void setUseSAO (Bool bVal) { m_bUseSAO = bVal; } + Bool getUseSAO () { return m_bUseSAO; } + Void setMaxNumOffsetsPerPic (Int iVal) { m_maxNumOffsetsPerPic = iVal; } + Int getMaxNumOffsetsPerPic () { return m_maxNumOffsetsPerPic; } + Void setSaoCtuBoundary (Bool val) { m_saoCtuBoundary = val; } + Bool getSaoCtuBoundary () { return m_saoCtuBoundary; } + Void setLFCrossTileBoundaryFlag ( Bool val ) { m_loopFilterAcrossTilesEnabledFlag = val; } + Bool getLFCrossTileBoundaryFlag () { return m_loopFilterAcrossTilesEnabledFlag; } + Void setTileUniformSpacingFlag ( Bool b ) { m_tileUniformSpacingFlag = b; } + Bool getTileUniformSpacingFlag () { return m_tileUniformSpacingFlag; } + Void setNumColumnsMinus1 ( Int i ) { m_iNumColumnsMinus1 = i; } + Int getNumColumnsMinus1 () { return m_iNumColumnsMinus1; } + Void setColumnWidth ( const std::vector& columnWidth ) { m_tileColumnWidth = columnWidth; } + UInt getColumnWidth ( UInt columnIdx ) { return m_tileColumnWidth[columnIdx]; } + Void setNumRowsMinus1 ( Int i ) { m_iNumRowsMinus1 = i; } + Int getNumRowsMinus1 () { return m_iNumRowsMinus1; } + Void setRowHeight ( const std::vector& rowHeight) { m_tileRowHeight = rowHeight; } + UInt getRowHeight ( UInt rowIdx ) { return m_tileRowHeight[rowIdx]; } + Void xCheckGSParameters(); + Void setWaveFrontSynchro(Int iWaveFrontSynchro) { m_iWaveFrontSynchro = iWaveFrontSynchro; } + Int getWaveFrontsynchro() { return m_iWaveFrontSynchro; } + Void setWaveFrontSubstreams(Int iWaveFrontSubstreams) { m_iWaveFrontSubstreams = iWaveFrontSubstreams; } + Int getWaveFrontSubstreams() { return m_iWaveFrontSubstreams; } + Void setDecodedPictureHashSEIEnabled(Int b) { m_decodedPictureHashSEIEnabled = b; } + Int getDecodedPictureHashSEIEnabled() { return m_decodedPictureHashSEIEnabled; } + Void setBufferingPeriodSEIEnabled(Int b) { m_bufferingPeriodSEIEnabled = b; } + Int getBufferingPeriodSEIEnabled() { return m_bufferingPeriodSEIEnabled; } + Void setPictureTimingSEIEnabled(Int b) { m_pictureTimingSEIEnabled = b; } + Int getPictureTimingSEIEnabled() { return m_pictureTimingSEIEnabled; } + Void setRecoveryPointSEIEnabled(Int b) { m_recoveryPointSEIEnabled = b; } + Int getRecoveryPointSEIEnabled() { return m_recoveryPointSEIEnabled; } + Void setToneMappingInfoSEIEnabled(Bool b) { m_toneMappingInfoSEIEnabled = b; } + Bool getToneMappingInfoSEIEnabled() { return m_toneMappingInfoSEIEnabled; } + Void setTMISEIToneMapId(Int b) { m_toneMapId = b; } + Int getTMISEIToneMapId() { return m_toneMapId; } + Void setTMISEIToneMapCancelFlag(Bool b) { m_toneMapCancelFlag=b; } + Bool getTMISEIToneMapCancelFlag() { return m_toneMapCancelFlag; } + Void setTMISEIToneMapPersistenceFlag(Bool b) { m_toneMapPersistenceFlag = b; } + Bool getTMISEIToneMapPersistenceFlag() { return m_toneMapPersistenceFlag; } + Void setTMISEICodedDataBitDepth(Int b) { m_codedDataBitDepth = b; } + Int getTMISEICodedDataBitDepth() { return m_codedDataBitDepth; } + Void setTMISEITargetBitDepth(Int b) { m_targetBitDepth = b; } + Int getTMISEITargetBitDepth() { return m_targetBitDepth; } + Void setTMISEIModelID(Int b) { m_modelId = b; } + Int getTMISEIModelID() { return m_modelId; } + Void setTMISEIMinValue(Int b) { m_minValue = b; } + Int getTMISEIMinValue() { return m_minValue; } + Void setTMISEIMaxValue(Int b) { m_maxValue = b; } + Int getTMISEIMaxValue() { return m_maxValue; } + Void setTMISEISigmoidMidpoint(Int b) { m_sigmoidMidpoint = b; } + Int getTMISEISigmoidMidpoint() { return m_sigmoidMidpoint; } + Void setTMISEISigmoidWidth(Int b) { m_sigmoidWidth = b; } + Int getTMISEISigmoidWidth() { return m_sigmoidWidth; } + Void setTMISEIStartOfCodedInterva( Int* p ) { m_startOfCodedInterval = p; } + Int* getTMISEIStartOfCodedInterva() { return m_startOfCodedInterval; } + Void setTMISEINumPivots(Int b) { m_numPivots = b; } + Int getTMISEINumPivots() { return m_numPivots; } + Void setTMISEICodedPivotValue( Int* p ) { m_codedPivotValue = p; } + Int* getTMISEICodedPivotValue() { return m_codedPivotValue; } + Void setTMISEITargetPivotValue( Int* p ) { m_targetPivotValue = p; } + Int* getTMISEITargetPivotValue() { return m_targetPivotValue; } + Void setTMISEICameraIsoSpeedIdc(Int b) { m_cameraIsoSpeedIdc = b; } + Int getTMISEICameraIsoSpeedIdc() { return m_cameraIsoSpeedIdc; } + Void setTMISEICameraIsoSpeedValue(Int b) { m_cameraIsoSpeedValue = b; } + Int getTMISEICameraIsoSpeedValue() { return m_cameraIsoSpeedValue; } + Void setTMISEIExposureIndexIdc(Int b) { m_exposureIndexIdc = b; } + Int getTMISEIExposurIndexIdc() { return m_exposureIndexIdc; } + Void setTMISEIExposureIndexValue(Int b) { m_exposureIndexValue = b; } + Int getTMISEIExposurIndexValue() { return m_exposureIndexValue; } + Void setTMISEIExposureCompensationValueSignFlag(Int b) { m_exposureCompensationValueSignFlag = b; } + Int getTMISEIExposureCompensationValueSignFlag() { return m_exposureCompensationValueSignFlag; } + Void setTMISEIExposureCompensationValueNumerator(Int b) { m_exposureCompensationValueNumerator = b; } + Int getTMISEIExposureCompensationValueNumerator() { return m_exposureCompensationValueNumerator; } + Void setTMISEIExposureCompensationValueDenomIdc(Int b) { m_exposureCompensationValueDenomIdc =b; } + Int getTMISEIExposureCompensationValueDenomIdc() { return m_exposureCompensationValueDenomIdc; } + Void setTMISEIRefScreenLuminanceWhite(Int b) { m_refScreenLuminanceWhite = b; } + Int getTMISEIRefScreenLuminanceWhite() { return m_refScreenLuminanceWhite; } + Void setTMISEIExtendedRangeWhiteLevel(Int b) { m_extendedRangeWhiteLevel = b; } + Int getTMISEIExtendedRangeWhiteLevel() { return m_extendedRangeWhiteLevel; } + Void setTMISEINominalBlackLevelLumaCodeValue(Int b) { m_nominalBlackLevelLumaCodeValue = b; } + Int getTMISEINominalBlackLevelLumaCodeValue() { return m_nominalBlackLevelLumaCodeValue; } + Void setTMISEINominalWhiteLevelLumaCodeValue(Int b) { m_nominalWhiteLevelLumaCodeValue = b; } + Int getTMISEINominalWhiteLevelLumaCodeValue() { return m_nominalWhiteLevelLumaCodeValue; } + Void setTMISEIExtendedWhiteLevelLumaCodeValue(Int b) { m_extendedWhiteLevelLumaCodeValue =b; } + Int getTMISEIExtendedWhiteLevelLumaCodeValue() { return m_extendedWhiteLevelLumaCodeValue; } + Void setFramePackingArrangementSEIEnabled(Int b) { m_framePackingSEIEnabled = b; } + Int getFramePackingArrangementSEIEnabled() { return m_framePackingSEIEnabled; } + Void setFramePackingArrangementSEIType(Int b) { m_framePackingSEIType = b; } + Int getFramePackingArrangementSEIType() { return m_framePackingSEIType; } + Void setFramePackingArrangementSEIId(Int b) { m_framePackingSEIId = b; } + Int getFramePackingArrangementSEIId() { return m_framePackingSEIId; } + Void setFramePackingArrangementSEIQuincunx(Int b) { m_framePackingSEIQuincunx = b; } + Int getFramePackingArrangementSEIQuincunx() { return m_framePackingSEIQuincunx; } + Void setFramePackingArrangementSEIInterpretation(Int b) { m_framePackingSEIInterpretation = b; } + Int getFramePackingArrangementSEIInterpretation() { return m_framePackingSEIInterpretation; } + Void setSegmentedRectFramePackingArrangementSEIEnabled(Int b) { m_segmentedRectFramePackingSEIEnabled = b; } + Int getSegmentedRectFramePackingArrangementSEIEnabled() { return m_segmentedRectFramePackingSEIEnabled; } + Void setSegmentedRectFramePackingArrangementSEICancel(Int b) { m_segmentedRectFramePackingSEICancel = b; } + Int getSegmentedRectFramePackingArrangementSEICancel() { return m_segmentedRectFramePackingSEICancel; } + Void setSegmentedRectFramePackingArrangementSEIType(Int b) { m_segmentedRectFramePackingSEIType = b; } + Int getSegmentedRectFramePackingArrangementSEIType() { return m_segmentedRectFramePackingSEIType; } + Void setSegmentedRectFramePackingArrangementSEIPersistence(Int b) { m_segmentedRectFramePackingSEIPersistence = b; } + Int getSegmentedRectFramePackingArrangementSEIPersistence() { return m_segmentedRectFramePackingSEIPersistence; } + Void setDisplayOrientationSEIAngle(Int b) { m_displayOrientationSEIAngle = b; } + Int getDisplayOrientationSEIAngle() { return m_displayOrientationSEIAngle; } + Void setTemporalLevel0IndexSEIEnabled(Int b) { m_temporalLevel0IndexSEIEnabled = b; } + Int getTemporalLevel0IndexSEIEnabled() { return m_temporalLevel0IndexSEIEnabled; } + Void setGradualDecodingRefreshInfoEnabled(Int b) { m_gradualDecodingRefreshInfoEnabled = b; } + Int getGradualDecodingRefreshInfoEnabled() { return m_gradualDecodingRefreshInfoEnabled; } + Void setNoDisplaySEITLayer(Int b) { m_noDisplaySEITLayer = b; } + Int getNoDisplaySEITLayer() { return m_noDisplaySEITLayer; } + Void setDecodingUnitInfoSEIEnabled(Int b) { m_decodingUnitInfoSEIEnabled = b; } + Int getDecodingUnitInfoSEIEnabled() { return m_decodingUnitInfoSEIEnabled; } + Void setSOPDescriptionSEIEnabled(Int b) { m_SOPDescriptionSEIEnabled = b; } + Int getSOPDescriptionSEIEnabled() { return m_SOPDescriptionSEIEnabled; } + Void setScalableNestingSEIEnabled(Int b) { m_scalableNestingSEIEnabled = b; } + Int getScalableNestingSEIEnabled() { return m_scalableNestingSEIEnabled; } + Void setTMCTSSEIEnabled(Bool b) { m_tmctsSEIEnabled = b; } + Bool getTMCTSSEIEnabled() { return m_tmctsSEIEnabled; } + Void setTimeCodeSEIEnabled(Bool b) { m_timeCodeSEIEnabled = b; } + Bool getTimeCodeSEIEnabled() { return m_timeCodeSEIEnabled; } + Void setNumberOfTimeSets(Int value) { m_timeCodeSEINumTs = value; } + Int getNumberOfTimesets() { return m_timeCodeSEINumTs; } + Void setTimeSet(TComSEITimeSet element, Int index) { m_timeSetArray[index] = element; } + TComSEITimeSet &getTimeSet(Int index) { return m_timeSetArray[index]; } + const TComSEITimeSet &getTimeSet(Int index) const { return m_timeSetArray[index]; } + Void setKneeSEIEnabled(Int b) { m_kneeSEIEnabled = b; } + Bool getKneeSEIEnabled() { return m_kneeSEIEnabled; } + Void setKneeSEIId(Int b) { m_kneeSEIId = b; } + Int getKneeSEIId() { return m_kneeSEIId; } + Void setKneeSEICancelFlag(Bool b) { m_kneeSEICancelFlag=b; } + Bool getKneeSEICancelFlag() { return m_kneeSEICancelFlag; } + Void setKneeSEIPersistenceFlag(Bool b) { m_kneeSEIPersistenceFlag = b; } + Bool getKneeSEIPersistenceFlag() { return m_kneeSEIPersistenceFlag; } + Void setKneeSEIInputDrange(Int b) { m_kneeSEIInputDrange = b; } + Int getKneeSEIInputDrange() { return m_kneeSEIInputDrange; } + Void setKneeSEIInputDispLuminance(Int b) { m_kneeSEIInputDispLuminance = b; } + Int getKneeSEIInputDispLuminance() { return m_kneeSEIInputDispLuminance; } + Void setKneeSEIOutputDrange(Int b) { m_kneeSEIOutputDrange = b; } + Int getKneeSEIOutputDrange() { return m_kneeSEIOutputDrange; } + Void setKneeSEIOutputDispLuminance(Int b) { m_kneeSEIOutputDispLuminance = b; } + Int getKneeSEIOutputDispLuminance() { return m_kneeSEIOutputDispLuminance; } + Void setKneeSEINumKneePointsMinus1(Int b) { m_kneeSEINumKneePointsMinus1 = b; } + Int getKneeSEINumKneePointsMinus1() { return m_kneeSEINumKneePointsMinus1; } + Void setKneeSEIInputKneePoint(Int *p) { m_kneeSEIInputKneePoint = p; } + Int* getKneeSEIInputKneePoint() { return m_kneeSEIInputKneePoint; } + Void setKneeSEIOutputKneePoint(Int *p) { m_kneeSEIOutputKneePoint = p; } + Int* getKneeSEIOutputKneePoint() { return m_kneeSEIOutputKneePoint; } + Void setMasteringDisplaySEI(const TComSEIMasteringDisplay &src) { m_masteringDisplay = src; } + const TComSEIMasteringDisplay &getMasteringDisplaySEI() const { return m_masteringDisplay; } + Void setUseWP ( Bool b ) { m_useWeightedPred = b; } + Void setWPBiPred ( Bool b ) { m_useWeightedBiPred = b; } + Bool getUseWP () { return m_useWeightedPred; } + Bool getWPBiPred () { return m_useWeightedBiPred; } + Void setLog2ParallelMergeLevelMinus2 ( UInt u ) { m_log2ParallelMergeLevelMinus2 = u; } + UInt getLog2ParallelMergeLevelMinus2 () { return m_log2ParallelMergeLevelMinus2; } + Void setMaxNumMergeCand ( UInt u ) { m_maxNumMergeCand = u; } + UInt getMaxNumMergeCand () { return m_maxNumMergeCand; } + Void setUseScalingListId ( ScalingListMode u ) { m_useScalingListId = u; } + ScalingListMode getUseScalingListId () { return m_useScalingListId; } + Void setScalingListFile ( Char* pch ) { m_scalingListFile = pch; } + Char* getScalingListFile () { return m_scalingListFile; } + Void setTMVPModeId ( Int u ) { m_TMVPModeId = u; } + Int getTMVPModeId () { return m_TMVPModeId; } + Void setSignHideFlag( Int signHideFlag ) { m_signHideFlag = signHideFlag; } + Int getSignHideFlag() { return m_signHideFlag; } + Bool getUseRateCtrl () { return m_RCEnableRateControl; } + Void setUseRateCtrl ( Bool b ) { m_RCEnableRateControl = b; } + Int getTargetBitrate () { return m_RCTargetBitrate; } + Void setTargetBitrate ( Int bitrate ) { m_RCTargetBitrate = bitrate; } + Int getKeepHierBit () { return m_RCKeepHierarchicalBit; } + Void setKeepHierBit ( Int i ) { m_RCKeepHierarchicalBit = i; } + Bool getLCULevelRC () { return m_RCLCULevelRC; } + Void setLCULevelRC ( Bool b ) { m_RCLCULevelRC = b; } + Bool getUseLCUSeparateModel () { return m_RCUseLCUSeparateModel; } + Void setUseLCUSeparateModel ( Bool b ) { m_RCUseLCUSeparateModel = b; } + Int getInitialQP () { return m_RCInitialQP; } + Void setInitialQP ( Int QP ) { m_RCInitialQP = QP; } + Bool getForceIntraQP () { return m_RCForceIntraQP; } + Void setForceIntraQP ( Bool b ) { m_RCForceIntraQP = b; } + Bool getTransquantBypassEnableFlag() { return m_TransquantBypassEnableFlag; } + Void setTransquantBypassEnableFlag(Bool flag) { m_TransquantBypassEnableFlag = flag; } + Bool getCUTransquantBypassFlagForceValue() { return m_CUTransquantBypassFlagForce; } + Void setCUTransquantBypassFlagForceValue(Bool flag) { m_CUTransquantBypassFlagForce = flag; } + CostMode getCostMode( ) { return m_costMode; } + Void setCostMode(CostMode m ) { m_costMode = m; } + + Void setVPS(TComVPS *p) { m_cVPS = *p; } + TComVPS * getVPS() { return &m_cVPS; } + Void setUseRecalculateQPAccordingToLambda (Bool b) { m_recalculateQPAccordingToLambda = b; } + Bool getUseRecalculateQPAccordingToLambda () { return m_recalculateQPAccordingToLambda; } + + Void setUseStrongIntraSmoothing ( Bool b ) { m_useStrongIntraSmoothing = b; } + Bool getUseStrongIntraSmoothing () { return m_useStrongIntraSmoothing; } + + Void setActiveParameterSetsSEIEnabled ( Int b ) { m_activeParameterSetsSEIEnabled = b; } + Int getActiveParameterSetsSEIEnabled () { return m_activeParameterSetsSEIEnabled; } + Bool getVuiParametersPresentFlag() { return m_vuiParametersPresentFlag; } + Void setVuiParametersPresentFlag(Bool i) { m_vuiParametersPresentFlag = i; } + Bool getAspectRatioInfoPresentFlag() { return m_aspectRatioInfoPresentFlag; } + Void setAspectRatioInfoPresentFlag(Bool i) { m_aspectRatioInfoPresentFlag = i; } + Int getAspectRatioIdc() { return m_aspectRatioIdc; } + Void setAspectRatioIdc(Int i) { m_aspectRatioIdc = i; } + Int getSarWidth() { return m_sarWidth; } + Void setSarWidth(Int i) { m_sarWidth = i; } + Int getSarHeight() { return m_sarHeight; } + Void setSarHeight(Int i) { m_sarHeight = i; } + Bool getOverscanInfoPresentFlag() { return m_overscanInfoPresentFlag; } + Void setOverscanInfoPresentFlag(Bool i) { m_overscanInfoPresentFlag = i; } + Bool getOverscanAppropriateFlag() { return m_overscanAppropriateFlag; } + Void setOverscanAppropriateFlag(Bool i) { m_overscanAppropriateFlag = i; } + Bool getVideoSignalTypePresentFlag() { return m_videoSignalTypePresentFlag; } + Void setVideoSignalTypePresentFlag(Bool i) { m_videoSignalTypePresentFlag = i; } + Int getVideoFormat() { return m_videoFormat; } + Void setVideoFormat(Int i) { m_videoFormat = i; } + Bool getVideoFullRangeFlag() { return m_videoFullRangeFlag; } + Void setVideoFullRangeFlag(Bool i) { m_videoFullRangeFlag = i; } + Bool getColourDescriptionPresentFlag() { return m_colourDescriptionPresentFlag; } + Void setColourDescriptionPresentFlag(Bool i) { m_colourDescriptionPresentFlag = i; } + Int getColourPrimaries() { return m_colourPrimaries; } + Void setColourPrimaries(Int i) { m_colourPrimaries = i; } + Int getTransferCharacteristics() { return m_transferCharacteristics; } + Void setTransferCharacteristics(Int i) { m_transferCharacteristics = i; } + Int getMatrixCoefficients() { return m_matrixCoefficients; } + Void setMatrixCoefficients(Int i) { m_matrixCoefficients = i; } + Bool getChromaLocInfoPresentFlag() { return m_chromaLocInfoPresentFlag; } + Void setChromaLocInfoPresentFlag(Bool i) { m_chromaLocInfoPresentFlag = i; } + Int getChromaSampleLocTypeTopField() { return m_chromaSampleLocTypeTopField; } + Void setChromaSampleLocTypeTopField(Int i) { m_chromaSampleLocTypeTopField = i; } + Int getChromaSampleLocTypeBottomField() { return m_chromaSampleLocTypeBottomField; } + Void setChromaSampleLocTypeBottomField(Int i) { m_chromaSampleLocTypeBottomField = i; } + Bool getNeutralChromaIndicationFlag() { return m_neutralChromaIndicationFlag; } + Void setNeutralChromaIndicationFlag(Bool i) { m_neutralChromaIndicationFlag = i; } + Window &getDefaultDisplayWindow() { return m_defaultDisplayWindow; } + Void setDefaultDisplayWindow (Int offsetLeft, Int offsetRight, Int offsetTop, Int offsetBottom ) { m_defaultDisplayWindow.setWindow (offsetLeft, offsetRight, offsetTop, offsetBottom); } + Bool getFrameFieldInfoPresentFlag() { return m_frameFieldInfoPresentFlag; } + Void setFrameFieldInfoPresentFlag(Bool i) { m_frameFieldInfoPresentFlag = i; } + Bool getPocProportionalToTimingFlag() { return m_pocProportionalToTimingFlag; } + Void setPocProportionalToTimingFlag(Bool x) { m_pocProportionalToTimingFlag = x; } + Int getNumTicksPocDiffOneMinus1() { return m_numTicksPocDiffOneMinus1; } + Void setNumTicksPocDiffOneMinus1(Int x) { m_numTicksPocDiffOneMinus1 = x; } + Bool getBitstreamRestrictionFlag() { return m_bitstreamRestrictionFlag; } + Void setBitstreamRestrictionFlag(Bool i) { m_bitstreamRestrictionFlag = i; } + Bool getTilesFixedStructureFlag() { return m_tilesFixedStructureFlag; } + Void setTilesFixedStructureFlag(Bool i) { m_tilesFixedStructureFlag = i; } + Bool getMotionVectorsOverPicBoundariesFlag() { return m_motionVectorsOverPicBoundariesFlag; } + Void setMotionVectorsOverPicBoundariesFlag(Bool i) { m_motionVectorsOverPicBoundariesFlag = i; } + Int getMinSpatialSegmentationIdc() { return m_minSpatialSegmentationIdc; } + Void setMinSpatialSegmentationIdc(Int i) { m_minSpatialSegmentationIdc = i; } + Int getMaxBytesPerPicDenom() { return m_maxBytesPerPicDenom; } + Void setMaxBytesPerPicDenom(Int i) { m_maxBytesPerPicDenom = i; } + Int getMaxBitsPerMinCuDenom() { return m_maxBitsPerMinCuDenom; } + Void setMaxBitsPerMinCuDenom(Int i) { m_maxBitsPerMinCuDenom = i; } + Int getLog2MaxMvLengthHorizontal() { return m_log2MaxMvLengthHorizontal; } + Void setLog2MaxMvLengthHorizontal(Int i) { m_log2MaxMvLengthHorizontal = i; } + Int getLog2MaxMvLengthVertical() { return m_log2MaxMvLengthVertical; } + Void setLog2MaxMvLengthVertical(Int i) { m_log2MaxMvLengthVertical = i; } + + Bool getProgressiveSourceFlag() const { return m_progressiveSourceFlag; } + Void setProgressiveSourceFlag(Bool b) { m_progressiveSourceFlag = b; } + + Bool getInterlacedSourceFlag() const { return m_interlacedSourceFlag; } + Void setInterlacedSourceFlag(Bool b) { m_interlacedSourceFlag = b; } + + Bool getNonPackedConstraintFlag() const { return m_nonPackedConstraintFlag; } + Void setNonPackedConstraintFlag(Bool b) { m_nonPackedConstraintFlag = b; } + + Bool getFrameOnlyConstraintFlag() const { return m_frameOnlyConstraintFlag; } + Void setFrameOnlyConstraintFlag(Bool b) { m_frameOnlyConstraintFlag = b; } + + UInt getBitDepthConstraintValue() const { return m_bitDepthConstraintValue; } + Void setBitDepthConstraintValue(UInt v) { m_bitDepthConstraintValue=v; } + + ChromaFormat getChromaFormatConstraintValue() const { return m_chromaFormatConstraintValue; } + Void setChromaFormatConstraintValue(ChromaFormat v) { m_chromaFormatConstraintValue=v; } + + Bool getIntraConstraintFlag() const { return m_intraConstraintFlag; } + Void setIntraConstraintFlag(Bool b) { m_intraConstraintFlag=b; } + + Bool getLowerBitRateConstraintFlag() const { return m_lowerBitRateConstraintFlag; } + Void setLowerBitRateConstraintFlag(Bool b) { m_lowerBitRateConstraintFlag=b; } + Bool getChromaSamplingFilterHintEnabled() { return m_chromaSamplingFilterHintEnabled;} + Void setChromaSamplingFilterHintEnabled(Bool i) { m_chromaSamplingFilterHintEnabled = i;} + Int getChromaSamplingHorFilterIdc() { return m_chromaSamplingHorFilterIdc;} + Void setChromaSamplingHorFilterIdc(Int i) { m_chromaSamplingHorFilterIdc = i;} + Int getChromaSamplingVerFilterIdc() { return m_chromaSamplingVerFilterIdc;} + Void setChromaSamplingVerFilterIdc(Int i) { m_chromaSamplingVerFilterIdc = i;} +}; + +//! \} + +#endif // !defined(AFX_TENCCFG_H__6B99B797_F4DA_4E46_8E78_7656339A6C41__INCLUDED_) diff --git a/jctvc/TLibEncoder/TEncCu.cpp b/jctvc/TLibEncoder/TEncCu.cpp new file mode 100644 index 0000000..19d516a --- /dev/null +++ b/jctvc/TLibEncoder/TEncCu.cpp @@ -0,0 +1,1649 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncCu.cpp + \brief Coding Unit (CU) encoder class +*/ + +#include +#include "TEncTop.h" +#include "TEncCu.h" +#include "TEncAnalyze.h" +#include "TLibCommon/Debug.h" + +#include +#include +using namespace std; + + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +/** + \param uiTotalDepth total number of allowable depth + \param uiMaxWidth largest CU width + \param uiMaxHeight largest CU height + */ +Void TEncCu::create(UChar uhTotalDepth, UInt uiMaxWidth, UInt uiMaxHeight, ChromaFormat chromaFormat) +{ + Int i; + + m_uhTotalDepth = uhTotalDepth + 1; + m_ppcBestCU = new TComDataCU*[m_uhTotalDepth-1]; + m_ppcTempCU = new TComDataCU*[m_uhTotalDepth-1]; + + m_ppcPredYuvBest = new TComYuv*[m_uhTotalDepth-1]; + m_ppcResiYuvBest = new TComYuv*[m_uhTotalDepth-1]; + m_ppcRecoYuvBest = new TComYuv*[m_uhTotalDepth-1]; + m_ppcPredYuvTemp = new TComYuv*[m_uhTotalDepth-1]; + m_ppcResiYuvTemp = new TComYuv*[m_uhTotalDepth-1]; + m_ppcRecoYuvTemp = new TComYuv*[m_uhTotalDepth-1]; + m_ppcOrigYuv = new TComYuv*[m_uhTotalDepth-1]; + + UInt uiNumPartitions; + for( i=0 ; i> i; + UInt uiHeight = uiMaxHeight >> i; + + m_ppcBestCU[i] = new TComDataCU; m_ppcBestCU[i]->create( chromaFormat, uiNumPartitions, uiWidth, uiHeight, false, uiMaxWidth >> (m_uhTotalDepth - 1) ); + m_ppcTempCU[i] = new TComDataCU; m_ppcTempCU[i]->create( chromaFormat, uiNumPartitions, uiWidth, uiHeight, false, uiMaxWidth >> (m_uhTotalDepth - 1) ); + + m_ppcPredYuvBest[i] = new TComYuv; m_ppcPredYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); + m_ppcResiYuvBest[i] = new TComYuv; m_ppcResiYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); + m_ppcRecoYuvBest[i] = new TComYuv; m_ppcRecoYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); + + m_ppcPredYuvTemp[i] = new TComYuv; m_ppcPredYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); + m_ppcResiYuvTemp[i] = new TComYuv; m_ppcResiYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); + m_ppcRecoYuvTemp[i] = new TComYuv; m_ppcRecoYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); + + m_ppcOrigYuv [i] = new TComYuv; m_ppcOrigYuv [i]->create(uiWidth, uiHeight, chromaFormat); + } + + m_bEncodeDQP = false; + m_CodeChromaQpAdjFlag = false; + m_ChromaQpAdjIdc = 0; + + // initialize partition order. + UInt* piTmp = &g_auiZscanToRaster[0]; + initZscanToRaster( m_uhTotalDepth, 1, 0, piTmp); + initRasterToZscan( uiMaxWidth, uiMaxHeight, m_uhTotalDepth ); + + // initialize conversion matrix from partition index to pel + initRasterToPelXY( uiMaxWidth, uiMaxHeight, m_uhTotalDepth ); +} + +Void TEncCu::destroy() +{ + Int i; + + for( i=0 ; idestroy(); delete m_ppcBestCU[i]; m_ppcBestCU[i] = NULL; + } + if(m_ppcTempCU[i]) + { + m_ppcTempCU[i]->destroy(); delete m_ppcTempCU[i]; m_ppcTempCU[i] = NULL; + } + if(m_ppcPredYuvBest[i]) + { + m_ppcPredYuvBest[i]->destroy(); delete m_ppcPredYuvBest[i]; m_ppcPredYuvBest[i] = NULL; + } + if(m_ppcResiYuvBest[i]) + { + m_ppcResiYuvBest[i]->destroy(); delete m_ppcResiYuvBest[i]; m_ppcResiYuvBest[i] = NULL; + } + if(m_ppcRecoYuvBest[i]) + { + m_ppcRecoYuvBest[i]->destroy(); delete m_ppcRecoYuvBest[i]; m_ppcRecoYuvBest[i] = NULL; + } + if(m_ppcPredYuvTemp[i]) + { + m_ppcPredYuvTemp[i]->destroy(); delete m_ppcPredYuvTemp[i]; m_ppcPredYuvTemp[i] = NULL; + } + if(m_ppcResiYuvTemp[i]) + { + m_ppcResiYuvTemp[i]->destroy(); delete m_ppcResiYuvTemp[i]; m_ppcResiYuvTemp[i] = NULL; + } + if(m_ppcRecoYuvTemp[i]) + { + m_ppcRecoYuvTemp[i]->destroy(); delete m_ppcRecoYuvTemp[i]; m_ppcRecoYuvTemp[i] = NULL; + } + if(m_ppcOrigYuv[i]) + { + m_ppcOrigYuv[i]->destroy(); delete m_ppcOrigYuv[i]; m_ppcOrigYuv[i] = NULL; + } + } + if(m_ppcBestCU) + { + delete [] m_ppcBestCU; + m_ppcBestCU = NULL; + } + if(m_ppcTempCU) + { + delete [] m_ppcTempCU; + m_ppcTempCU = NULL; + } + + if(m_ppcPredYuvBest) + { + delete [] m_ppcPredYuvBest; + m_ppcPredYuvBest = NULL; + } + if(m_ppcResiYuvBest) + { + delete [] m_ppcResiYuvBest; + m_ppcResiYuvBest = NULL; + } + if(m_ppcRecoYuvBest) + { + delete [] m_ppcRecoYuvBest; + m_ppcRecoYuvBest = NULL; + } + if(m_ppcPredYuvTemp) + { + delete [] m_ppcPredYuvTemp; + m_ppcPredYuvTemp = NULL; + } + if(m_ppcResiYuvTemp) + { + delete [] m_ppcResiYuvTemp; + m_ppcResiYuvTemp = NULL; + } + if(m_ppcRecoYuvTemp) + { + delete [] m_ppcRecoYuvTemp; + m_ppcRecoYuvTemp = NULL; + } + if(m_ppcOrigYuv) + { + delete [] m_ppcOrigYuv; + m_ppcOrigYuv = NULL; + } +} + +/** \param pcEncTop pointer of encoder class + */ +Void TEncCu::init( TEncTop* pcEncTop ) +{ + m_pcEncCfg = pcEncTop; + m_pcPredSearch = pcEncTop->getPredSearch(); + m_pcTrQuant = pcEncTop->getTrQuant(); + m_pcRdCost = pcEncTop->getRdCost(); + + m_pcEntropyCoder = pcEncTop->getEntropyCoder(); + m_pcBinCABAC = pcEncTop->getBinCABAC(); + + m_pppcRDSbacCoder = pcEncTop->getRDSbacCoder(); + m_pcRDGoOnSbacCoder = pcEncTop->getRDGoOnSbacCoder(); + + m_pcRateCtrl = pcEncTop->getRateCtrl(); +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** \param rpcCU pointer of CU data class + */ +Void TEncCu::compressCtu( TComDataCU* pCtu ) +{ + // initialize CU data + m_ppcBestCU[0]->initCtu( pCtu->getPic(), pCtu->getCtuRsAddr() ); + m_ppcTempCU[0]->initCtu( pCtu->getPic(), pCtu->getCtuRsAddr() ); + + // analysis of CU + DEBUG_STRING_NEW(sDebug) + + xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 DEBUG_STRING_PASS_INTO(sDebug) ); + DEBUG_STRING_OUTPUT(std::cout, sDebug) + +#if ADAPTIVE_QP_SELECTION + if( m_pcEncCfg->getUseAdaptQpSelect() ) + { + if(pCtu->getSlice()->getSliceType()!=I_SLICE) //IIII + { + xCtuCollectARLStats( pCtu ); + } + } +#endif +} +/** \param pcCU pointer of CU data class + */ +Void TEncCu::encodeCtu ( TComDataCU* pCtu ) +{ + if ( pCtu->getSlice()->getPPS()->getUseDQP() ) + { + setdQPFlag(true); + } + + if ( pCtu->getSlice()->getUseChromaQpAdj() ) + { + setCodeChromaQpAdjFlag(true); + } + + // Encode CU data + xEncodeCU( pCtu, 0, 0 ); +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== +/** Derive small set of test modes for AMP encoder speed-up + *\param rpcBestCU + *\param eParentPartSize + *\param bTestAMP_Hor + *\param bTestAMP_Ver + *\param bTestMergeAMP_Hor + *\param bTestMergeAMP_Ver + *\returns Void +*/ +#if AMP_ENC_SPEEDUP +#if AMP_MRG +Void TEncCu::deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver, Bool &bTestMergeAMP_Hor, Bool &bTestMergeAMP_Ver) +#else +Void TEncCu::deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver) +#endif +{ + if ( pcBestCU->getPartitionSize(0) == SIZE_2NxN ) + { + bTestAMP_Hor = true; + } + else if ( pcBestCU->getPartitionSize(0) == SIZE_Nx2N ) + { + bTestAMP_Ver = true; + } + else if ( pcBestCU->getPartitionSize(0) == SIZE_2Nx2N && pcBestCU->getMergeFlag(0) == false && pcBestCU->isSkipped(0) == false ) + { + bTestAMP_Hor = true; + bTestAMP_Ver = true; + } + +#if AMP_MRG + //! Utilizing the partition size of parent PU + if ( eParentPartSize >= SIZE_2NxnU && eParentPartSize <= SIZE_nRx2N ) + { + bTestMergeAMP_Hor = true; + bTestMergeAMP_Ver = true; + } + + if ( eParentPartSize == NUMBER_OF_PART_SIZES ) //! if parent is intra + { + if ( pcBestCU->getPartitionSize(0) == SIZE_2NxN ) + { + bTestMergeAMP_Hor = true; + } + else if ( pcBestCU->getPartitionSize(0) == SIZE_Nx2N ) + { + bTestMergeAMP_Ver = true; + } + } + + if ( pcBestCU->getPartitionSize(0) == SIZE_2Nx2N && pcBestCU->isSkipped(0) == false ) + { + bTestMergeAMP_Hor = true; + bTestMergeAMP_Ver = true; + } + + if ( pcBestCU->getWidth(0) == 64 ) + { + bTestAMP_Hor = false; + bTestAMP_Ver = false; + } +#else + //! Utilizing the partition size of parent PU + if ( eParentPartSize >= SIZE_2NxnU && eParentPartSize <= SIZE_nRx2N ) + { + bTestAMP_Hor = true; + bTestAMP_Ver = true; + } + + if ( eParentPartSize == SIZE_2Nx2N ) + { + bTestAMP_Hor = false; + bTestAMP_Ver = false; + } +#endif +} +#endif + + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== +/** Compress a CU block recursively with enabling sub-CTU-level delta QP + *\param rpcBestCU + *\param rpcTempCU + *\param uiDepth + *\returns Void + * + *- for loop of QP value to compress the current CU with all possible QP +*/ +#if AMP_ENC_SPEEDUP +Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize ) +#else +Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth ) +#endif +{ + TComPic* pcPic = rpcBestCU->getPic(); + DEBUG_STRING_NEW(sDebug) + + // get Original YUV data from picture + m_ppcOrigYuv[uiDepth]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() ); + + // variable for Early CU determination + Bool bSubBranch = true; + + // variable for Cbf fast mode PU decision + Bool doNotBlockPu = true; + Bool earlyDetectionSkipMode = false; + + Bool bBoundary = false; + UInt uiLPelX = rpcBestCU->getCUPelX(); + UInt uiRPelX = uiLPelX + rpcBestCU->getWidth(0) - 1; + UInt uiTPelY = rpcBestCU->getCUPelY(); + UInt uiBPelY = uiTPelY + rpcBestCU->getHeight(0) - 1; + + Int iBaseQP = xComputeQP( rpcBestCU, uiDepth ); + Int iMinQP; + Int iMaxQP; + Bool isAddLowestQP = false; + + const UInt numberValidComponents = rpcBestCU->getPic()->getNumberValidComponents(); + + if( (g_uiMaxCUWidth>>uiDepth) >= rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) + { + Int idQP = m_pcEncCfg->getMaxDeltaQP(); + iMinQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP ); + iMaxQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP ); + } + else + { + iMinQP = rpcTempCU->getQP(0); + iMaxQP = rpcTempCU->getQP(0); + } + + if ( m_pcEncCfg->getUseRateCtrl() ) + { + iMinQP = m_pcRateCtrl->getRCQP(); + iMaxQP = m_pcRateCtrl->getRCQP(); + } + + // transquant-bypass (TQB) processing loop variable initialisation --- + + const Int lowestQP = iMinQP; // For TQB, use this QP which is the lowest non TQB QP tested (rather than QP'=0) - that way delta QPs are smaller, and TQB can be tested at all CU levels. + + if ( (rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) ) + { + isAddLowestQP = true; // mark that the first iteration is to cost TQB mode. + iMinQP = iMinQP - 1; // increase loop variable range by 1, to allow testing of TQB mode along with other QPs + if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() ) + { + iMaxQP = iMinQP; + } + } + + TComSlice * pcSlice = rpcTempCU->getPic()->getSlice(rpcTempCU->getPic()->getCurrSliceIdx()); + // We need to split, so don't try these modes. + if ( ( uiRPelX < rpcBestCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && + ( uiBPelY < rpcBestCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) ) + { + for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) + { + const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); + + if (bIsLosslessMode) + { + iQP = lowestQP; + } + + m_ChromaQpAdjIdc = 0; + if (pcSlice->getUseChromaQpAdj()) + { + /* Pre-estimation of chroma QP based on input block activity may be performed + * here, using for example m_ppcOrigYuv[uiDepth] */ + /* To exercise the current code, the index used for adjustment is based on + * block position + */ + Int lgMinCuSize = pcSlice->getSPS()->getLog2MinCodingBlockSize(); + m_ChromaQpAdjIdc = ((uiLPelX >> lgMinCuSize) + (uiTPelY >> lgMinCuSize)) % (pcSlice->getPPS()->getChromaQpAdjTableSize() + 1); + } + + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + + // do inter modes, SKIP and 2Nx2N + if( rpcBestCU->getSlice()->getSliceType() != I_SLICE ) + { + // 2Nx2N + if(m_pcEncCfg->getUseEarlySkipDetection()) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );//by Competition for inter_2Nx2N + } + // SKIP + xCheckRDCostMerge2Nx2N( rpcBestCU, rpcTempCU DEBUG_STRING_PASS_INTO(sDebug), &earlyDetectionSkipMode );//by Merge for inter_2Nx2N + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + + if(!m_pcEncCfg->getUseEarlySkipDetection()) + { + // 2Nx2N, NxN + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode()) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + } + + if (bIsLosslessMode) // Restore loop variable if lossless mode was searched. + { + iQP = iMinQP; + } + } + + if(!earlyDetectionSkipMode) + { + for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) + { + const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); // If lossless, then iQP is irrelevant for subsequent modules. + + if (bIsLosslessMode) + { + iQP = lowestQP; + } + + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + + // do inter modes, NxN, 2NxN, and Nx2N + if( rpcBestCU->getSlice()->getSliceType() != I_SLICE ) + { + // 2Nx2N, NxN + if(!( (rpcBestCU->getWidth(0)==8) && (rpcBestCU->getHeight(0)==8) )) + { + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth && doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + } + } + + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_Nx2N ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + if(doNotBlockPu) + { + xCheckRDCostInter ( rpcBestCU, rpcTempCU, SIZE_2NxN DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxN) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + + //! Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N) + if( pcPic->getSlice(0)->getSPS()->getAMPAcc(uiDepth) ) + { +#if AMP_ENC_SPEEDUP + Bool bTestAMP_Hor = false, bTestAMP_Ver = false; + +#if AMP_MRG + Bool bTestMergeAMP_Hor = false, bTestMergeAMP_Ver = false; + + deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver, bTestMergeAMP_Hor, bTestMergeAMP_Ver); +#else + deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver); +#endif + + //! Do horizontal AMP + if ( bTestAMP_Hor ) + { + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + } +#if AMP_MRG + else if ( bTestMergeAMP_Hor ) + { + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug), true ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug), true ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + } +#endif + + //! Do horizontal AMP + if ( bTestAMP_Ver ) + { + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + } + } +#if AMP_MRG + else if ( bTestMergeAMP_Ver ) + { + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug), true ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ) + { + doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; + } + } + if(doNotBlockPu) + { + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug), true ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + } + } +#endif + +#else + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + + xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + +#endif + } + } + + // do normal intra modes + // speedup for inter frames + Double intraCost = 0.0; + + if((rpcBestCU->getSlice()->getSliceType() == I_SLICE) || + (rpcBestCU->getCbf( 0, COMPONENT_Y ) != 0) || + ((rpcBestCU->getCbf( 0, COMPONENT_Cb ) != 0) && (numberValidComponents > COMPONENT_Cb)) || + ((rpcBestCU->getCbf( 0, COMPONENT_Cr ) != 0) && (numberValidComponents > COMPONENT_Cr)) ) // avoid very complex intra if it is unlikely + { + xCheckRDCostIntra( rpcBestCU, rpcTempCU, intraCost, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth ) + { + if( rpcTempCU->getWidth(0) > ( 1 << rpcTempCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) ) + { + Double tmpIntraCost; + xCheckRDCostIntra( rpcBestCU, rpcTempCU, tmpIntraCost, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug) ); + intraCost = std::min(intraCost, tmpIntraCost); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + } + } + } + + // test PCM + if(pcPic->getSlice(0)->getSPS()->getUsePCM() + && rpcTempCU->getWidth(0) <= (1<getSlice(0)->getSPS()->getPCMLog2MaxSize()) + && rpcTempCU->getWidth(0) >= (1<getSlice(0)->getSPS()->getPCMLog2MinSize()) ) + { + UInt uiRawBits = getTotalBits(rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), rpcBestCU->getPic()->getChromaFormat(), g_bitDepth); + UInt uiBestBits = rpcBestCU->getTotalBits(); + if((uiBestBits > uiRawBits) || (rpcBestCU->getTotalCost() > m_pcRdCost->calcRdCost(uiRawBits, 0))) + { + xCheckIntraPCM (rpcBestCU, rpcTempCU); + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + } + } + + if (bIsLosslessMode) // Restore loop variable if lossless mode was searched. + { + iQP = iMinQP; + } + } + } + + m_pcEntropyCoder->resetBits(); + m_pcEntropyCoder->encodeSplitFlag( rpcBestCU, 0, uiDepth, true ); + rpcBestCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits + rpcBestCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + rpcBestCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcBestCU->getTotalBits(), rpcBestCU->getTotalDistortion() ); + + // Early CU determination + if( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->isSkipped(0) ) + { + bSubBranch = false; + } + else + { + bSubBranch = true; + } + } + else + { + bBoundary = true; + } + + // copy orginal YUV samples to PCM buffer + if( rpcBestCU->isLosslessCoded(0) && (rpcBestCU->getIPCMFlag(0) == false)) + { + xFillPCMBuffer(rpcBestCU, m_ppcOrigYuv[uiDepth]); + } + + if( (g_uiMaxCUWidth>>uiDepth) == rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) + { + Int idQP = m_pcEncCfg->getMaxDeltaQP(); + iMinQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP ); + iMaxQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP ); + } + else if( (g_uiMaxCUWidth>>uiDepth) > rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) + { + iMinQP = iBaseQP; + iMaxQP = iBaseQP; + } + else + { + const Int iStartQP = rpcTempCU->getQP(0); + iMinQP = iStartQP; + iMaxQP = iStartQP; + } + + if ( m_pcEncCfg->getUseRateCtrl() ) + { + iMinQP = m_pcRateCtrl->getRCQP(); + iMaxQP = m_pcRateCtrl->getRCQP(); + } + + if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() ) + { + iMaxQP = iMinQP; // If all TUs are forced into using transquant bypass, do not loop here. + } + + for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) + { + const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true. + + rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); + + // further split + if( bSubBranch && uiDepth < g_uiMaxCUDepth - g_uiAddCUDepth ) + { + UChar uhNextDepth = uiDepth+1; + TComDataCU* pcSubBestPartCU = m_ppcBestCU[uhNextDepth]; + TComDataCU* pcSubTempPartCU = m_ppcTempCU[uhNextDepth]; + DEBUG_STRING_NEW(sTempDebug) + + for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ ) + { + pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. + pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. + + if( ( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) + { + if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer + { + m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); + } + else + { + m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]); + } + +#if AMP_ENC_SPEEDUP + DEBUG_STRING_NEW(sChild) + if ( !rpcBestCU->isInter(0) ) + { + xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), NUMBER_OF_PART_SIZES ); + } + else + { + + xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), rpcBestCU->getPartitionSize(0) ); + } + DEBUG_STRING_APPEND(sTempDebug, sChild) +#else + xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth ); +#endif + + rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); // Keep best part data to current temporary data. + xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth ); + } + else + { + pcSubBestPartCU->copyToPic( uhNextDepth ); + rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); + } + } + + if( !bBoundary ) + { + m_pcEntropyCoder->resetBits(); + m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true ); + + rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits + rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + } + rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); + + if( (g_uiMaxCUWidth>>uiDepth) == rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() && rpcTempCU->getSlice()->getPPS()->getUseDQP()) + { + Bool hasResidual = false; + for( UInt uiBlkIdx = 0; uiBlkIdx < rpcTempCU->getTotalNumPart(); uiBlkIdx ++) + { + if( ( rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y) + || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb)) + || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) ) ) + { + hasResidual = true; + break; + } + } + + UInt uiTargetPartIdx = 0; + if ( hasResidual ) + { +#if !RDO_WITHOUT_DQP_BITS + m_pcEntropyCoder->resetBits(); + m_pcEntropyCoder->encodeQP( rpcTempCU, uiTargetPartIdx, false ); + rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits + rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); +#endif + + Bool foundNonZeroCbf = false; + rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( uiTargetPartIdx ), 0, uiDepth, foundNonZeroCbf ); + assert( foundNonZeroCbf ); + } + else + { + rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( uiTargetPartIdx ), 0, uiDepth ); // set QP to default QP + } + } + + m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); + + // TODO: this does not account for the slice bytes already written. See other instances of FIXED_NUMBER_OF_BYTES + Bool isEndOfSlice = rpcBestCU->getSlice()->getSliceMode()==FIXED_NUMBER_OF_BYTES + && (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceArgument()<<3); + Bool isEndOfSliceSegment = rpcBestCU->getSlice()->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES + && (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceSegmentArgument()<<3); + if(isEndOfSlice||isEndOfSliceSegment) + { + if (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING) + rpcBestCU->getTotalCost()=rpcTempCU->getTotalCost() + (1.0 / m_pcRdCost->getLambda()); + else + rpcBestCU->getTotalCost()=rpcTempCU->getTotalCost()+1; + } + + xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction + // with sub partitioned prediction. + } + } + + DEBUG_STRING_APPEND(sDebug_, sDebug); + + rpcBestCU->copyToPic(uiDepth); // Copy Best data to Picture for next partition prediction. + + xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth, rpcBestCU, uiLPelX, uiTPelY ); // Copy Yuv data to picture Yuv + if (bBoundary) + { + return; + } + + // Assert if Best prediction mode is NONE + // Selected mode's RD-cost must be not MAX_DOUBLE. + assert( rpcBestCU->getPartitionSize ( 0 ) != NUMBER_OF_PART_SIZES ); + assert( rpcBestCU->getPredictionMode( 0 ) != NUMBER_OF_PREDICTION_MODES ); + assert( rpcBestCU->getTotalCost ( ) != MAX_DOUBLE ); +} + +/** finish encoding a cu and handle end-of-slice conditions + * \param pcCU + * \param uiAbsPartIdx + * \param uiDepth + * \returns Void + */ +Void TEncCu::finishCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + TComPic* pcPic = pcCU->getPic(); + TComSlice * pcSlice = pcCU->getPic()->getSlice(pcCU->getPic()->getCurrSliceIdx()); + + //Calculate end address + const Int currentCTUTsAddr = pcPic->getPicSym()->getCtuRsToTsAddrMap(pcCU->getCtuRsAddr()); + const Bool isLastSubCUOfCtu = pcCU->isLastSubCUOfCtu(uiAbsPartIdx); + if ( isLastSubCUOfCtu ) + { + // The 1-terminating bit is added to all streams, so don't add it here when it's 1. + // i.e. when the slice segment CurEnd CTU address is the current CTU address+1. + if (pcSlice->getSliceSegmentCurEndCtuTsAddr() != currentCTUTsAddr+1) + { + m_pcEntropyCoder->encodeTerminatingBit( 0 ); + } + } +} + +/** Compute QP for each CU + * \param pcCU Target CU + * \param uiDepth CU depth + * \returns quantization parameter + */ +Int TEncCu::xComputeQP( TComDataCU* pcCU, UInt uiDepth ) +{ + Int iBaseQp = pcCU->getSlice()->getSliceQp(); + Int iQpOffset = 0; + if ( m_pcEncCfg->getUseAdaptiveQP() ) + { + TEncPic* pcEPic = dynamic_cast( pcCU->getPic() ); + UInt uiAQDepth = min( uiDepth, pcEPic->getMaxAQDepth()-1 ); + TEncPicQPAdaptationLayer* pcAQLayer = pcEPic->getAQLayer( uiAQDepth ); + UInt uiAQUPosX = pcCU->getCUPelX() / pcAQLayer->getAQPartWidth(); + UInt uiAQUPosY = pcCU->getCUPelY() / pcAQLayer->getAQPartHeight(); + UInt uiAQUStride = pcAQLayer->getAQPartStride(); + TEncQPAdaptationUnit* acAQU = pcAQLayer->getQPAdaptationUnit(); + + Double dMaxQScale = pow(2.0, m_pcEncCfg->getQPAdaptationRange()/6.0); + Double dAvgAct = pcAQLayer->getAvgActivity(); + Double dCUAct = acAQU[uiAQUPosY * uiAQUStride + uiAQUPosX].getActivity(); + Double dNormAct = (dMaxQScale*dCUAct + dAvgAct) / (dCUAct + dMaxQScale*dAvgAct); + Double dQpOffset = log(dNormAct) / log(2.0) * 6.0; + iQpOffset = Int(floor( dQpOffset + 0.49999 )); + } + + return Clip3(-pcCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQp+iQpOffset ); +} + +/** encode a CU block recursively + * \param pcCU + * \param uiAbsPartIdx + * \param uiDepth + * \returns Void + */ +Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + TComPic* pcPic = pcCU->getPic(); + + Bool bBoundary = false; + UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ]; + UInt uiRPelX = uiLPelX + (g_uiMaxCUWidth>>uiDepth) - 1; + UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ]; + UInt uiBPelY = uiTPelY + (g_uiMaxCUHeight>>uiDepth) - 1; + + TComSlice * pcSlice = pcCU->getPic()->getSlice(pcCU->getPic()->getCurrSliceIdx()); + if( ( uiRPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) + { + m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth ); + } + else + { + bBoundary = true; + } + + if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < (g_uiMaxCUDepth-g_uiAddCUDepth) ) ) || bBoundary ) + { + UInt uiQNumParts = ( pcPic->getNumPartitionsInCtu() >> (uiDepth<<1) )>>2; + if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP()) + { + setdQPFlag(true); + } + + if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuChromaQpAdjSize() && pcCU->getSlice()->getUseChromaQpAdj()) + { + setCodeChromaQpAdjFlag(true); + } + + for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++, uiAbsPartIdx+=uiQNumParts ) + { + uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ]; + uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ]; + if( ( uiLPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) + { + xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1 ); + } + } + return; + } + + if( (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP()) + { + setdQPFlag(true); + } + + if( (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuChromaQpAdjSize() && pcCU->getSlice()->getUseChromaQpAdj()) + { + setCodeChromaQpAdjFlag(true); + } + + if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag( pcCU, uiAbsPartIdx ); + } + + if( !pcCU->getSlice()->isIntra() ) + { + m_pcEntropyCoder->encodeSkipFlag( pcCU, uiAbsPartIdx ); + } + + if( pcCU->isSkipped( uiAbsPartIdx ) ) + { + m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx ); + finishCU(pcCU,uiAbsPartIdx,uiDepth); + return; + } + + m_pcEntropyCoder->encodePredMode( pcCU, uiAbsPartIdx ); + m_pcEntropyCoder->encodePartSize( pcCU, uiAbsPartIdx, uiDepth ); + + if (pcCU->isIntra( uiAbsPartIdx ) && pcCU->getPartitionSize( uiAbsPartIdx ) == SIZE_2Nx2N ) + { + m_pcEntropyCoder->encodeIPCMInfo( pcCU, uiAbsPartIdx ); + + if(pcCU->getIPCMFlag(uiAbsPartIdx)) + { + // Encode slice finish + finishCU(pcCU,uiAbsPartIdx,uiDepth); + return; + } + } + + // prediction Info ( Intra : direction mode, Inter : Mv, reference idx ) + m_pcEntropyCoder->encodePredInfo( pcCU, uiAbsPartIdx ); + + // Encode Coefficients + Bool bCodeDQP = getdQPFlag(); + Bool codeChromaQpAdj = getCodeChromaQpAdjFlag(); + m_pcEntropyCoder->encodeCoeff( pcCU, uiAbsPartIdx, uiDepth, bCodeDQP, codeChromaQpAdj ); + setCodeChromaQpAdjFlag( codeChromaQpAdj ); + setdQPFlag( bCodeDQP ); + + // --- write terminating bit --- + finishCU(pcCU,uiAbsPartIdx,uiDepth); +} + +Int xCalcHADs8x8_ISlice(Pel *piOrg, Int iStrideOrg) +{ + Int k, i, j, jj; + Int diff[64], m1[8][8], m2[8][8], m3[8][8], iSumHad = 0; + + for( k = 0; k < 64; k += 8 ) + { + diff[k+0] = piOrg[0] ; + diff[k+1] = piOrg[1] ; + diff[k+2] = piOrg[2] ; + diff[k+3] = piOrg[3] ; + diff[k+4] = piOrg[4] ; + diff[k+5] = piOrg[5] ; + diff[k+6] = piOrg[6] ; + diff[k+7] = piOrg[7] ; + + piOrg += iStrideOrg; + } + + //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 (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + iSumHad += abs(m2[i][j]); + } + } + iSumHad -= abs(m2[0][0]); + iSumHad =(iSumHad+2)>>2; + return(iSumHad); +} + +Int TEncCu::updateCtuDataISlice(TComDataCU* pCtu, Int width, Int height) +{ + Int xBl, yBl; + const Int iBlkSize = 8; + + Pel* pOrgInit = pCtu->getPic()->getPicYuvOrg()->getAddr(COMPONENT_Y, pCtu->getCtuRsAddr(), 0); + Int iStrideOrig = pCtu->getPic()->getPicYuvOrg()->getStride(COMPONENT_Y); + Pel *pOrg; + + Int iSumHad = 0; + for ( yBl=0; (yBl+iBlkSize)<=height; yBl+= iBlkSize) + { + for ( xBl=0; (xBl+iBlkSize)<=width; xBl+= iBlkSize) + { + pOrg = pOrgInit + iStrideOrig*yBl + xBl; + iSumHad += xCalcHADs8x8_ISlice(pOrg, iStrideOrig); + } + } + return(iSumHad); +} + +/** check RD costs for a CU block encoded with merge + * \param rpcBestCU + * \param rpcTempCU + * \returns Void + */ +Void TEncCu::xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU DEBUG_STRING_FN_DECLARE(sDebug), Bool *earlyDetectionSkipMode ) +{ + assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE ); + TComMvField cMvFieldNeighbours[2 * MRG_MAX_NUM_CANDS]; // double length for mv of both lists + UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS]; + Int numValidMergeCand = 0; + const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0); + + for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui ) + { + uhInterDirNeighbours[ui] = 0; + } + UChar uhDepth = rpcTempCU->getDepth( 0 ); + rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand ); + + Int mergeCandBuffer[MRG_MAX_NUM_CANDS]; + for( UInt ui = 0; ui < numValidMergeCand; ++ui ) + { + mergeCandBuffer[ui] = 0; + } + + Bool bestIsSkip = false; + + UInt iteration; + if ( rpcTempCU->isLosslessCoded(0)) + { + iteration = 1; + } + else + { + iteration = 2; + } + DEBUG_STRING_NEW(bestStr) + + for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ) + { + for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand ) + { + if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1)) + { + if( !(bestIsSkip && uiNoResidual == 0) ) + { + DEBUG_STRING_NEW(tmpStr) + // set MC parameters + rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth ); + rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_ChromaQpAdjIdc, 0, uhDepth ); + rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to CTU level + rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level + rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level + + // do MC + m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] ); + // estimate residual and encode everything + m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, + m_ppcOrigYuv [uhDepth], + m_ppcPredYuvTemp[uhDepth], + m_ppcResiYuvTemp[uhDepth], + m_ppcResiYuvBest[uhDepth], + m_ppcRecoYuvTemp[uhDepth], + (uiNoResidual != 0) DEBUG_STRING_PASS_INTO(tmpStr) ); + +#ifdef DEBUG_STRING + DebugInterPredResiReco(tmpStr, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0))); +#endif + + if ((uiNoResidual == 0) && (rpcTempCU->getQtRootCbf(0) == 0)) + { + // If no residual when allowing for one, then set mark to not try case where residual is forced to 0 + mergeCandBuffer[uiMergeCand] = 1; + } + + rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth ); + Int orgQP = rpcTempCU->getQP( 0 ); + xCheckDQP( rpcTempCU ); + xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(bestStr) DEBUG_STRING_PASS_INTO(tmpStr)); + + rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag ); + + if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) + { + bestIsSkip = rpcBestCU->getQtRootCbf(0) == 0; + } + } + } + } + + if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection()) + { + if(rpcBestCU->getQtRootCbf( 0 ) == 0) + { + if( rpcBestCU->getMergeFlag( 0 )) + { + *earlyDetectionSkipMode = true; + } + else if(m_pcEncCfg->getFastSearch() != SELECTIVE) + { + Int absoulte_MV=0; + for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) + { + if ( rpcBestCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 ) + { + TComCUMvField* pcCUMvField = rpcBestCU->getCUMvField(RefPicList( uiRefListIdx )); + Int iHor = pcCUMvField->getMvd( 0 ).getAbsHor(); + Int iVer = pcCUMvField->getMvd( 0 ).getAbsVer(); + absoulte_MV+=iHor+iVer; + } + } + + if(absoulte_MV == 0) + { + *earlyDetectionSkipMode = true; + } + } + } + } + } + DEBUG_STRING_APPEND(sDebug, bestStr) +} + + +#if AMP_MRG +Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG) +#else +Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize ) +#endif +{ + DEBUG_STRING_NEW(sTest) + + UChar uhDepth = rpcTempCU->getDepth( 0 ); + + rpcTempCU->setDepthSubParts( uhDepth, 0 ); + + rpcTempCU->setSkipFlagSubParts( false, 0, uhDepth ); + + rpcTempCU->setPartSizeSubParts ( ePartSize, 0, uhDepth ); + rpcTempCU->setPredModeSubParts ( MODE_INTER, 0, uhDepth ); + rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uhDepth ); + +#if AMP_MRG + rpcTempCU->setMergeAMP (true); + m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] DEBUG_STRING_PASS_INTO(sTest), false, bUseMRG ); +#else + m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] ); +#endif + +#if AMP_MRG + if ( !rpcTempCU->getMergeAMP() ) + { + return; + } +#endif + + m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false DEBUG_STRING_PASS_INTO(sTest) ); + rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); + +#ifdef DEBUG_STRING + DebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0))); +#endif + + xCheckDQP( rpcTempCU ); + xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest)); +} + +Void TEncCu::xCheckRDCostIntra( TComDataCU *&rpcBestCU, + TComDataCU *&rpcTempCU, + Double &cost, + PartSize eSize + DEBUG_STRING_FN_DECLARE(sDebug) ) +{ + DEBUG_STRING_NEW(sTest) + + UInt uiDepth = rpcTempCU->getDepth( 0 ); + + rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth ); + + rpcTempCU->setPartSizeSubParts( eSize, 0, uiDepth ); + rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth ); + rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uiDepth ); + + Bool bSeparateLumaChroma = true; // choose estimation mode + + Distortion uiPreCalcDistC = 0; + if (rpcBestCU->getPic()->getChromaFormat()==CHROMA_400) + { + bSeparateLumaChroma=true; + } + + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]; + + if( !bSeparateLumaChroma ) + { + // after this function, the direction will be PLANAR, DC, HOR or VER + // however, if Luma ends up being one of those, the chroma dir must be later changed to DM_CHROMA. + m_pcPredSearch->preestChromaPredMode( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth] ); + } + m_pcPredSearch->estIntraPredQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], resiLuma, uiPreCalcDistC, bSeparateLumaChroma DEBUG_STRING_PASS_INTO(sTest) ); + + m_ppcRecoYuvTemp[uiDepth]->copyToPicComponent(COMPONENT_Y, rpcTempCU->getPic()->getPicYuvRec(), rpcTempCU->getCtuRsAddr(), rpcTempCU->getZorderIdxInCtu() ); + + if (rpcBestCU->getPic()->getChromaFormat()!=CHROMA_400) + { + m_pcPredSearch->estIntraPredChromaQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], resiLuma, uiPreCalcDistC DEBUG_STRING_PASS_INTO(sTest) ); + } + + m_pcEntropyCoder->resetBits(); + + if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true ); + } + + m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true ); + m_pcEntropyCoder->encodePredMode( rpcTempCU, 0, true ); + m_pcEntropyCoder->encodePartSize( rpcTempCU, 0, uiDepth, true ); + m_pcEntropyCoder->encodePredInfo( rpcTempCU, 0 ); + m_pcEntropyCoder->encodeIPCMInfo(rpcTempCU, 0, true ); + + // Encode Coefficients + Bool bCodeDQP = getdQPFlag(); + Bool codeChromaQpAdjFlag = getCodeChromaQpAdjFlag(); + m_pcEntropyCoder->encodeCoeff( rpcTempCU, 0, uiDepth, bCodeDQP, codeChromaQpAdjFlag ); + setCodeChromaQpAdjFlag( codeChromaQpAdjFlag ); + setdQPFlag( bCodeDQP ); + + m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); + + rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits(); + rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); + + xCheckDQP( rpcTempCU ); + + cost = rpcTempCU->getTotalCost(); + + xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest)); +} + + +/** Check R-D costs for a CU with PCM mode. + * \param rpcBestCU pointer to best mode CU data structure + * \param rpcTempCU pointer to testing mode CU data structure + * \returns Void + * + * \note Current PCM implementation encodes sample values in a lossless way. The distortion of PCM mode CUs are zero. PCM mode is selected if the best mode yields bits greater than that of PCM mode. + */ +Void TEncCu::xCheckIntraPCM( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU ) +{ + UInt uiDepth = rpcTempCU->getDepth( 0 ); + + rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth ); + + rpcTempCU->setIPCMFlag(0, true); + rpcTempCU->setIPCMFlagSubParts (true, 0, rpcTempCU->getDepth(0)); + rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uiDepth ); + rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth ); + rpcTempCU->setTrIdxSubParts ( 0, 0, uiDepth ); + rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uiDepth ); + + m_pcPredSearch->IPCMSearch( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth]); + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); + + m_pcEntropyCoder->resetBits(); + + if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true ); + } + + m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true ); + m_pcEntropyCoder->encodePredMode ( rpcTempCU, 0, true ); + m_pcEntropyCoder->encodePartSize ( rpcTempCU, 0, uiDepth, true ); + m_pcEntropyCoder->encodeIPCMInfo ( rpcTempCU, 0, true ); + + m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); + + rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits(); + rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); + + xCheckDQP( rpcTempCU ); + DEBUG_STRING_NEW(a) + DEBUG_STRING_NEW(b) + xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(a) DEBUG_STRING_PASS_INTO(b)); +} + +/** check whether current try is the best with identifying the depth of current try + * \param rpcBestCU + * \param rpcTempCU + * \returns Void + */ +Void TEncCu::xCheckBestMode( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sParent) DEBUG_STRING_FN_DECLARE(sTest) DEBUG_STRING_PASS_INTO(Bool bAddSizeInfo) ) +{ + if( rpcTempCU->getTotalCost() < rpcBestCU->getTotalCost() ) + { + TComYuv* pcYuv; + // Change Information data + TComDataCU* pcCU = rpcBestCU; + rpcBestCU = rpcTempCU; + rpcTempCU = pcCU; + + // Change Prediction data + pcYuv = m_ppcPredYuvBest[uiDepth]; + m_ppcPredYuvBest[uiDepth] = m_ppcPredYuvTemp[uiDepth]; + m_ppcPredYuvTemp[uiDepth] = pcYuv; + + // Change Reconstruction data + pcYuv = m_ppcRecoYuvBest[uiDepth]; + m_ppcRecoYuvBest[uiDepth] = m_ppcRecoYuvTemp[uiDepth]; + m_ppcRecoYuvTemp[uiDepth] = pcYuv; + + pcYuv = NULL; + pcCU = NULL; + + // store temp best CI for next CU coding + m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]->store(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]); + + +#ifdef DEBUG_STRING + DEBUG_STRING_SWAP(sParent, sTest) + const PredMode predMode=rpcBestCU->getPredictionMode(0); + if ((DebugOptionList::DebugString_Structure.getInt()&DebugStringGetPredModeMask(predMode)) && bAddSizeInfo) + { + std::stringstream ss(stringstream::out); + ss <<"###: " << (predMode==MODE_INTRA?"Intra ":"Inter ") << partSizeToString[rpcBestCU->getPartitionSize(0)] << " CU at " << rpcBestCU->getCUPelX() << ", " << rpcBestCU->getCUPelY() << " width=" << UInt(rpcBestCU->getWidth(0)) << std::endl; + sParent+=ss.str(); + } +#endif + } +} + +Void TEncCu::xCheckDQP( TComDataCU* pcCU ) +{ + UInt uiDepth = pcCU->getDepth( 0 ); + + if( pcCU->getSlice()->getPPS()->getUseDQP() && (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuDQPSize() ) + { + if ( pcCU->getQtRootCbf( 0) ) + { +#if !RDO_WITHOUT_DQP_BITS + m_pcEntropyCoder->resetBits(); + m_pcEntropyCoder->encodeQP( pcCU, 0, false ); + pcCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits + pcCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); + pcCU->getTotalCost() = m_pcRdCost->calcRdCost( pcCU->getTotalBits(), pcCU->getTotalDistortion() ); +#endif + } + else + { + pcCU->setQPSubParts( pcCU->getRefQP( 0 ), 0, uiDepth ); // set QP to default QP + } + } +} + +Void TEncCu::xCopyAMVPInfo (AMVPInfo* pSrc, AMVPInfo* pDst) +{ + pDst->iN = pSrc->iN; + for (Int i = 0; i < pSrc->iN; i++) + { + pDst->m_acMvCand[i] = pSrc->m_acMvCand[i]; + } +} +Void TEncCu::xCopyYuv2Pic(TComPic* rpcPic, UInt uiCUAddr, UInt uiAbsPartIdx, UInt uiDepth, UInt uiSrcDepth, TComDataCU* pcCU, UInt uiLPelX, UInt uiTPelY ) +{ + UInt uiAbsPartIdxInRaster = g_auiZscanToRaster[uiAbsPartIdx]; + UInt uiSrcBlkWidth = rpcPic->getNumPartInCtuWidth() >> (uiSrcDepth); + UInt uiBlkWidth = rpcPic->getNumPartInCtuWidth() >> (uiDepth); + UInt uiPartIdxX = ( ( uiAbsPartIdxInRaster % rpcPic->getNumPartInCtuWidth() ) % uiSrcBlkWidth) / uiBlkWidth; + UInt uiPartIdxY = ( ( uiAbsPartIdxInRaster / rpcPic->getNumPartInCtuWidth() ) % uiSrcBlkWidth) / uiBlkWidth; + UInt uiPartIdx = uiPartIdxY * ( uiSrcBlkWidth / uiBlkWidth ) + uiPartIdxX; + m_ppcRecoYuvBest[uiSrcDepth]->copyToPicYuv( rpcPic->getPicYuvRec (), uiCUAddr, uiAbsPartIdx, uiDepth - uiSrcDepth, uiPartIdx); + + m_ppcPredYuvBest[uiSrcDepth]->copyToPicYuv( rpcPic->getPicYuvPred (), uiCUAddr, uiAbsPartIdx, uiDepth - uiSrcDepth, uiPartIdx); +} + +Void TEncCu::xCopyYuv2Tmp( UInt uiPartUnitIdx, UInt uiNextDepth ) +{ + UInt uiCurrDepth = uiNextDepth - 1; + m_ppcRecoYuvBest[uiNextDepth]->copyToPartYuv( m_ppcRecoYuvTemp[uiCurrDepth], uiPartUnitIdx ); + m_ppcPredYuvBest[uiNextDepth]->copyToPartYuv( m_ppcPredYuvBest[uiCurrDepth], uiPartUnitIdx); +} + +/** Function for filling the PCM buffer of a CU using its original sample array + * \param pcCU pointer to current CU + * \param pcOrgYuv pointer to original sample array + * \returns Void + */ +Void TEncCu::xFillPCMBuffer ( TComDataCU* pCU, TComYuv* pOrgYuv ) +{ + const ChromaFormat format = pCU->getPic()->getChromaFormat(); + const UInt numberValidComponents = getNumberValidComponents(format); + for (UInt componentIndex = 0; componentIndex < numberValidComponents; componentIndex++) + { + const ComponentID component = ComponentID(componentIndex); + + const UInt width = pCU->getWidth(0) >> getComponentScaleX(component, format); + const UInt height = pCU->getHeight(0) >> getComponentScaleY(component, format); + + Pel *source = pOrgYuv->getAddr(component, 0, width); + Pel *destination = pCU->getPCMSample(component); + + const UInt sourceStride = pOrgYuv->getStride(component); + + for (Int line = 0; line < height; line++) + { + for (Int column = 0; column < width; column++) + { + destination[column] = source[column]; + } + + source += sourceStride; + destination += width; + } + } +} + +#if ADAPTIVE_QP_SELECTION +/** Collect ARL statistics from one block + */ +Int TEncCu::xTuCollectARLStats(TCoeff* rpcCoeff, TCoeff* rpcArlCoeff, Int NumCoeffInCU, Double* cSum, UInt* numSamples ) +{ + for( Int n = 0; n < NumCoeffInCU; n++ ) + { + TCoeff u = abs( rpcCoeff[ n ] ); + TCoeff absc = rpcArlCoeff[ n ]; + + if( u != 0 ) + { + if( u < LEVEL_RANGE ) + { + cSum[ u ] += ( Double )absc; + numSamples[ u ]++; + } + else + { + cSum[ LEVEL_RANGE ] += ( Double )absc - ( Double )( u << ARL_C_PRECISION ); + numSamples[ LEVEL_RANGE ]++; + } + } + } + + return 0; +} + +/** Collect ARL statistics from one CTU + * \param pcCU + */ +Void TEncCu::xCtuCollectARLStats(TComDataCU* pCtu ) +{ + Double cSum[ LEVEL_RANGE + 1 ]; //: the sum of DCT coefficients corresponding to datatype and quantization output + UInt numSamples[ LEVEL_RANGE + 1 ]; //: the number of coefficients corresponding to datatype and quantization output + + TCoeff* pCoeffY = pCtu->getCoeff(COMPONENT_Y); + TCoeff* pArlCoeffY = pCtu->getArlCoeff(COMPONENT_Y); + + UInt uiMinCUWidth = g_uiMaxCUWidth >> g_uiMaxCUDepth; + UInt uiMinNumCoeffInCU = 1 << uiMinCUWidth; + + memset( cSum, 0, sizeof( Double )*(LEVEL_RANGE+1) ); + memset( numSamples, 0, sizeof( UInt )*(LEVEL_RANGE+1) ); + + // Collect stats to cSum[][] and numSamples[][] + for(Int i = 0; i < pCtu->getTotalNumPart(); i ++ ) + { + UInt uiTrIdx = pCtu->getTransformIdx(i); + + if(pCtu->isInter(i) && pCtu->getCbf( i, COMPONENT_Y, uiTrIdx ) ) + { + xTuCollectARLStats(pCoeffY, pArlCoeffY, uiMinNumCoeffInCU, cSum, numSamples); + }//Note that only InterY is processed. QP rounding is based on InterY data only. + + pCoeffY += uiMinNumCoeffInCU; + pArlCoeffY += uiMinNumCoeffInCU; + } + + for(Int u=1; ugetSliceSumC()[u] += cSum[ u ] ; + m_pcTrQuant->getSliceNSamples()[u] += numSamples[ u ] ; + } + m_pcTrQuant->getSliceSumC()[LEVEL_RANGE] += cSum[ LEVEL_RANGE ] ; + m_pcTrQuant->getSliceNSamples()[LEVEL_RANGE] += numSamples[ LEVEL_RANGE ] ; +} +#endif +//! \} diff --git a/jctvc/TLibEncoder/TEncCu.h b/jctvc/TLibEncoder/TEncCu.h new file mode 100644 index 0000000..a9ea413 --- /dev/null +++ b/jctvc/TLibEncoder/TEncCu.h @@ -0,0 +1,177 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncCu.h + \brief Coding Unit (CU) encoder class (header) +*/ + +#ifndef __TENCCU__ +#define __TENCCU__ + +// Include files +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComYuv.h" +#include "TLibCommon/TComPrediction.h" +#include "TLibCommon/TComTrQuant.h" +#include "TLibCommon/TComBitCounter.h" +#include "TLibCommon/TComDataCU.h" + +#include "TEncEntropy.h" +#include "TEncSearch.h" +#include "TEncRateCtrl.h" +//! \ingroup TLibEncoder +//! \{ + +class TEncTop; +class TEncSbac; +class TEncCavlc; +class TEncSlice; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// CU encoder class +class TEncCu +{ +private: + + TComDataCU** m_ppcBestCU; ///< Best CUs in each depth + TComDataCU** m_ppcTempCU; ///< Temporary CUs in each depth + UChar m_uhTotalDepth; + + TComYuv** m_ppcPredYuvBest; ///< Best Prediction Yuv for each depth + TComYuv** m_ppcResiYuvBest; ///< Best Residual Yuv for each depth + TComYuv** m_ppcRecoYuvBest; ///< Best Reconstruction Yuv for each depth + TComYuv** m_ppcPredYuvTemp; ///< Temporary Prediction Yuv for each depth + TComYuv** m_ppcResiYuvTemp; ///< Temporary Residual Yuv for each depth + TComYuv** m_ppcRecoYuvTemp; ///< Temporary Reconstruction Yuv for each depth + TComYuv** m_ppcOrigYuv; ///< Original Yuv for each depth + + // Data : encoder control + Bool m_bEncodeDQP; + Bool m_CodeChromaQpAdjFlag; + Int m_ChromaQpAdjIdc; + + // Access channel + TEncCfg* m_pcEncCfg; + TEncSearch* m_pcPredSearch; + TComTrQuant* m_pcTrQuant; + TComRdCost* m_pcRdCost; + + TEncEntropy* m_pcEntropyCoder; + TEncBinCABAC* m_pcBinCABAC; + + // SBAC RD + TEncSbac*** m_pppcRDSbacCoder; + TEncSbac* m_pcRDGoOnSbacCoder; + TEncRateCtrl* m_pcRateCtrl; + +public: + /// copy parameters from encoder class + Void init ( TEncTop* pcEncTop ); + + /// create internal buffers + Void create ( UChar uhTotalDepth, UInt iMaxWidth, UInt iMaxHeight, ChromaFormat chromaFormat ); + + /// destroy internal buffers + Void destroy (); + + /// CTU analysis function + Void compressCtu ( TComDataCU* pCtu ); + + /// CTU encoding function + Void encodeCtu ( TComDataCU* pCtu ); + + Int updateCtuDataISlice ( TComDataCU* pCtu, Int width, Int height ); + +protected: + Void finishCU ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ); +#if AMP_ENC_SPEEDUP + Void xCompressCU ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug), PartSize eParentPartSize = NUMBER_OF_PART_SIZES ); +#else + Void xCompressCU ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth ); +#endif + Void xEncodeCU ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ); + + Int xComputeQP ( TComDataCU* pcCU, UInt uiDepth ); + Void xCheckBestMode ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sParent) DEBUG_STRING_FN_DECLARE(sTest) DEBUG_STRING_PASS_INTO(Bool bAddSizeInfo=true)); + + Void xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU DEBUG_STRING_FN_DECLARE(sDebug), Bool *earlyDetectionSkipMode ); + +#if AMP_MRG + Void xCheckRDCostInter ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG = false ); +#else + Void xCheckRDCostInter ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize ); +#endif + + Void xCheckRDCostIntra ( TComDataCU *&rpcBestCU, + TComDataCU *&rpcTempCU, + Double &cost, + PartSize ePartSize + DEBUG_STRING_FN_DECLARE(sDebug) + ); + + Void xCheckDQP ( TComDataCU* pcCU ); + + Void xCheckIntraPCM ( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU ); + Void xCopyAMVPInfo ( AMVPInfo* pSrc, AMVPInfo* pDst ); + Void xCopyYuv2Pic (TComPic* rpcPic, UInt uiCUAddr, UInt uiAbsPartIdx, UInt uiDepth, UInt uiSrcDepth, TComDataCU* pcCU, UInt uiLPelX, UInt uiTPelY ); + Void xCopyYuv2Tmp ( UInt uhPartUnitIdx, UInt uiDepth ); + + Bool getdQPFlag () { return m_bEncodeDQP; } + Void setdQPFlag ( Bool b ) { m_bEncodeDQP = b; } + + Bool getCodeChromaQpAdjFlag() { return m_CodeChromaQpAdjFlag; } + Void setCodeChromaQpAdjFlag( Bool b ) { m_CodeChromaQpAdjFlag = b; } + +#if ADAPTIVE_QP_SELECTION + // Adaptive reconstruction level (ARL) statistics collection functions + Void xCtuCollectARLStats(TComDataCU* pCtu); + Int xTuCollectARLStats(TCoeff* rpcCoeff, TCoeff* rpcArlCoeff, Int NumCoeffInCU, Double* cSum, UInt* numSamples ); +#endif + +#if AMP_ENC_SPEEDUP +#if AMP_MRG + Void deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver, Bool &bTestMergeAMP_Hor, Bool &bTestMergeAMP_Ver); +#else + Void deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver); +#endif +#endif + + Void xFillPCMBuffer ( TComDataCU* pCU, TComYuv* pOrgYuv ); +}; + +//! \} + +#endif // __TENCMB__ diff --git a/jctvc/TLibEncoder/TEncEntropy.cpp b/jctvc/TLibEncoder/TEncEntropy.cpp new file mode 100644 index 0000000..d8788c3 --- /dev/null +++ b/jctvc/TLibEncoder/TEncEntropy.cpp @@ -0,0 +1,741 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncEntropy.cpp + \brief entropy encoder class +*/ + +#include "TEncEntropy.h" +#include "TLibCommon/TypeDef.h" +#include "TLibCommon/TComSampleAdaptiveOffset.h" +#include "TLibCommon/TComTU.h" + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST +#include "../TLibCommon/Debug.h" +static const Bool bDebugPredEnabled = DebugOptionList::DebugPred.getInt()!=0; +#endif + +//! \ingroup TLibEncoder +//! \{ + +Void TEncEntropy::setEntropyCoder ( TEncEntropyIf* e, TComSlice* pcSlice ) +{ + m_pcEntropyCoderIf = e; + m_pcEntropyCoderIf->setSlice ( pcSlice ); +} + +Void TEncEntropy::encodeSliceHeader ( TComSlice* pcSlice ) +{ + m_pcEntropyCoderIf->codeSliceHeader( pcSlice ); + return; +} + +Void TEncEntropy::encodeTilesWPPEntryPoint( TComSlice* pSlice ) +{ + m_pcEntropyCoderIf->codeTilesWPPEntryPoint( pSlice ); +} + +Void TEncEntropy::encodeTerminatingBit ( UInt uiIsLast ) +{ + m_pcEntropyCoderIf->codeTerminatingBit( uiIsLast ); + + return; +} + +Void TEncEntropy::encodeSliceFinish() +{ + m_pcEntropyCoderIf->codeSliceFinish(); +} + +Void TEncEntropy::encodePPS( TComPPS* pcPPS ) +{ + m_pcEntropyCoderIf->codePPS( pcPPS ); + return; +} + +Void TEncEntropy::encodeSPS( TComSPS* pcSPS ) +{ + m_pcEntropyCoderIf->codeSPS( pcSPS ); + return; +} + +Void TEncEntropy::encodeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + } + m_pcEntropyCoderIf->codeCUTransquantBypassFlag( pcCU, uiAbsPartIdx ); +} + +Void TEncEntropy::encodeVPS( TComVPS* pcVPS ) +{ + m_pcEntropyCoderIf->codeVPS( pcVPS ); + return; +} + +Void TEncEntropy::encodeSkipFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if ( pcCU->getSlice()->isIntra() ) + { + return; + } + if( bRD ) + { + uiAbsPartIdx = 0; + } + m_pcEntropyCoderIf->codeSkipFlag( pcCU, uiAbsPartIdx ); +} + +/** encode merge flag + * \param pcCU + * \param uiAbsPartIdx + * \returns Void + */ +Void TEncEntropy::encodeMergeFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + // at least one merge candidate exists + m_pcEntropyCoderIf->codeMergeFlag( pcCU, uiAbsPartIdx ); +} + +/** encode merge index + * \param pcCU + * \param uiAbsPartIdx + * \param bRD + * \returns Void + */ +Void TEncEntropy::encodeMergeIndex( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + assert( pcCU->getPartitionSize(uiAbsPartIdx) == SIZE_2Nx2N ); + } + m_pcEntropyCoderIf->codeMergeIndex( pcCU, uiAbsPartIdx ); +} + + +/** encode prediction mode + * \param pcCU + * \param uiAbsPartIdx + * \param bRD + * \returns Void + */ +Void TEncEntropy::encodePredMode( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + } + + if ( pcCU->getSlice()->isIntra() ) + { + return; + } + + m_pcEntropyCoderIf->codePredMode( pcCU, uiAbsPartIdx ); +} + +// Split mode +Void TEncEntropy::encodeSplitFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + } + + m_pcEntropyCoderIf->codeSplitFlag( pcCU, uiAbsPartIdx, uiDepth ); +} + +/** encode partition size + * \param pcCU + * \param uiAbsPartIdx + * \param uiDepth + * \param bRD + * \returns Void + */ +Void TEncEntropy::encodePartSize( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + } + + m_pcEntropyCoderIf->codePartSize( pcCU, uiAbsPartIdx, uiDepth ); +} + + +/** Encode I_PCM information. + * \param pcCU pointer to CU + * \param uiAbsPartIdx CU index + * \param bRD flag indicating estimation or encoding + * \returns Void + */ +Void TEncEntropy::encodeIPCMInfo( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if(!pcCU->getSlice()->getSPS()->getUsePCM() + || pcCU->getWidth(uiAbsPartIdx) > (1<getSlice()->getSPS()->getPCMLog2MaxSize()) + || pcCU->getWidth(uiAbsPartIdx) < (1<getSlice()->getSPS()->getPCMLog2MinSize())) + { + return; + } + + if( bRD ) + { + uiAbsPartIdx = 0; + } + + m_pcEntropyCoderIf->codeIPCMInfo ( pcCU, uiAbsPartIdx ); + +} + +Void TEncEntropy::xEncodeTransform( Bool& bCodeDQP, Bool& codeChromaQpAdj, TComTU &rTu ) +{ +//pcCU, absPartIdxCU, uiAbsPartIdx, uiDepth+1, uiTrIdx+1, quadrant, + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + const UInt numValidComponent = pcCU->getPic()->getNumberValidComponents(); + const Bool bChroma = isChromaEnabled(pcCU->getPic()->getChromaFormat()); + const UInt uiTrIdx = rTu.GetTransformDepthRel(); + const UInt uiDepth = rTu.GetTransformDepthTotal(); +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + const Bool bDebugRQT=g_bFinalEncode && DebugOptionList::DebugRQT.getInt()!=0; + if (bDebugRQT) + printf("x..codeTransform: offsetLuma=%d offsetChroma=%d absPartIdx=%d, uiDepth=%d\n width=%d, height=%d, uiTrIdx=%d, uiInnerQuadIdx=%d\n", + rTu.getCoefficientOffset(COMPONENT_Y), rTu.getCoefficientOffset(COMPONENT_Cb), uiAbsPartIdx, uiDepth, rTu.getRect(COMPONENT_Y).width, rTu.getRect(COMPONENT_Y).height, rTu.GetTransformDepthRel(), rTu.GetSectionNumber()); +#endif + const UInt uiSubdiv = pcCU->getTransformIdx( uiAbsPartIdx ) > uiTrIdx;// + pcCU->getDepth( uiAbsPartIdx ) > uiDepth; + const UInt uiLog2TrafoSize = rTu.GetLog2LumaTrSize(); + + + UInt cbf[MAX_NUM_COMPONENT] = {0,0,0}; + Bool bHaveACodedBlock = false; + Bool bHaveACodedChromaBlock = false; + + for(UInt ch=0; chgetCbf( uiAbsPartIdx, compID , uiTrIdx ); + + if (cbf[ch] != 0) + { + bHaveACodedBlock = true; + if (isChroma(compID)) bHaveACodedChromaBlock = true; + } + } + + if( pcCU->isIntra(uiAbsPartIdx) && pcCU->getPartitionSize(uiAbsPartIdx) == SIZE_NxN && uiDepth == pcCU->getDepth(uiAbsPartIdx) ) + { + assert( uiSubdiv ); + } + else if( pcCU->isInter(uiAbsPartIdx) && (pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N) && uiDepth == pcCU->getDepth(uiAbsPartIdx) && (pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) ) + { + if ( uiLog2TrafoSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) + { + assert( uiSubdiv ); + } + else + { + assert(!uiSubdiv ); + } + } + else if( uiLog2TrafoSize > pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() ) + { + assert( uiSubdiv ); + } + else if( uiLog2TrafoSize == pcCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) + { + assert( !uiSubdiv ); + } + else if( uiLog2TrafoSize == pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) + { + assert( !uiSubdiv ); + } + else + { + assert( uiLog2TrafoSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ); + m_pcEntropyCoderIf->codeTransformSubdivFlag( uiSubdiv, 5 - uiLog2TrafoSize ); + } + + const UInt uiTrDepthCurr = uiDepth - pcCU->getDepth( uiAbsPartIdx ); + const Bool bFirstCbfOfCU = uiTrDepthCurr == 0; + + for(UInt ch=COMPONENT_Cb; chgetCbf( uiAbsPartIdx, compID, uiTrDepthCurr - 1 ) ) + { + m_pcEntropyCoderIf->codeQtCbf( rTu, compID, (uiSubdiv == 0) ); + } + } + else + { + assert( pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepthCurr ) == pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepthCurr - 1 ) ); + } + } + + if( uiSubdiv ) + { + TComTURecurse tuRecurseChild(rTu, true); + do + { + xEncodeTransform( bCodeDQP, codeChromaQpAdj, tuRecurseChild ); + } + while (tuRecurseChild.nextSection(rTu)); + } + else + { + { + DTRACE_CABAC_VL( g_nSymbolCounter++ ); + DTRACE_CABAC_T( "\tTrIdx: abspart=" ); + DTRACE_CABAC_V( uiAbsPartIdx ); + DTRACE_CABAC_T( "\tdepth=" ); + DTRACE_CABAC_V( uiDepth ); + DTRACE_CABAC_T( "\ttrdepth=" ); + DTRACE_CABAC_V( pcCU->getTransformIdx( uiAbsPartIdx ) ); + DTRACE_CABAC_T( "\n" ); + } + + if( !pcCU->isIntra(uiAbsPartIdx) && uiDepth == pcCU->getDepth( uiAbsPartIdx ) && (!bChroma || (!pcCU->getCbf( uiAbsPartIdx, COMPONENT_Cb, 0 ) && !pcCU->getCbf( uiAbsPartIdx, COMPONENT_Cr, 0 ) ) ) ) + { + assert( pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, 0 ) ); + // printf( "saved one bin! " ); + } + else + { + m_pcEntropyCoderIf->codeQtCbf( rTu, COMPONENT_Y, true ); //luma CBF is always at the lowest level + } + + if ( bHaveACodedBlock ) + { + // dQP: only for CTU once + if ( pcCU->getSlice()->getPPS()->getUseDQP() ) + { + if ( bCodeDQP ) + { + encodeQP( pcCU, rTu.GetAbsPartIdxCU() ); + bCodeDQP = false; + } + } + + if ( pcCU->getSlice()->getUseChromaQpAdj() ) + { + if ( bHaveACodedChromaBlock && codeChromaQpAdj && !pcCU->getCUTransquantBypass(rTu.GetAbsPartIdxCU()) ) + { + encodeChromaQpAdjustment( pcCU, rTu.GetAbsPartIdxCU() ); + codeChromaQpAdj = false; + } + } + + const UInt numValidComp=pcCU->getPic()->getNumberValidComponents(); + + for(UInt ch=COMPONENT_Y; chgetCbf(subTUIterator.GetAbsPartIdxTU(compID), compID, (uiTrIdx + 1)); + + if (subTUCBF != 0) + { +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (bDebugRQT) printf("Call NxN for chan %d width=%d height=%d cbf=%d\n", compID, subTUIterator.getRect(compID).width, subTUIterator.getRect(compID).height, 1); +#endif + m_pcEntropyCoderIf->codeCoeffNxN( subTUIterator, (pcCU->getCoeff(compID) + subTUIterator.getCoefficientOffset(compID)), compID ); + } + } + while (subTUIterator.nextSection(rTu)); + } + else + { + if (isChroma(compID) && (cbf[COMPONENT_Y] != 0)) + { + m_pcEntropyCoderIf->codeCrossComponentPrediction( rTu, compID ); + } + + if (cbf[compID] != 0) + { + m_pcEntropyCoderIf->codeCoeffNxN( rTu, (pcCU->getCoeff(compID) + rTu.getCoefficientOffset(compID)), compID ); + } + } + } + } + } + } +} + + +// Intra direction for Luma +Void TEncEntropy::encodeIntraDirModeLuma ( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiplePU ) +{ + m_pcEntropyCoderIf->codeIntraDirLumaAng( pcCU, absPartIdx , isMultiplePU); +} + + +// Intra direction for Chroma +Void TEncEntropy::encodeIntraDirModeChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + m_pcEntropyCoderIf->codeIntraDirChroma( pcCU, uiAbsPartIdx ); + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (bDebugPredEnabled && g_bFinalEncode) + { + UInt cdir=pcCU->getIntraDir(CHANNEL_TYPE_CHROMA, uiAbsPartIdx); + if (cdir==36) cdir=pcCU->getIntraDir(CHANNEL_TYPE_LUMA, uiAbsPartIdx); + printf("coding chroma Intra dir: %d, uiAbsPartIdx: %d, luma dir: %d\n", cdir, uiAbsPartIdx, pcCU->getIntraDir(CHANNEL_TYPE_LUMA, uiAbsPartIdx)); + } +#endif +} + + +Void TEncEntropy::encodePredInfo( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + if( pcCU->isIntra( uiAbsPartIdx ) ) // If it is Intra mode, encode intra prediction mode. + { + encodeIntraDirModeLuma ( pcCU, uiAbsPartIdx,true ); + if (pcCU->getPic()->getChromaFormat()!=CHROMA_400) + { + encodeIntraDirModeChroma( pcCU, uiAbsPartIdx ); + + if (enable4ChromaPUsInIntraNxNCU(pcCU->getPic()->getChromaFormat()) && pcCU->getPartitionSize( uiAbsPartIdx )==SIZE_NxN) + { + UInt uiPartOffset = ( pcCU->getPic()->getNumPartitionsInCtu() >> ( pcCU->getDepth(uiAbsPartIdx) << 1 ) ) >> 2; + encodeIntraDirModeChroma( pcCU, uiAbsPartIdx + uiPartOffset ); + encodeIntraDirModeChroma( pcCU, uiAbsPartIdx + uiPartOffset*2 ); + encodeIntraDirModeChroma( pcCU, uiAbsPartIdx + uiPartOffset*3 ); + } + } + } + else // if it is Inter mode, encode motion vector and reference index + { + encodePUWise( pcCU, uiAbsPartIdx ); + } +} + +Void TEncEntropy::encodeCrossComponentPrediction( TComTU &rTu, ComponentID compID ) +{ + m_pcEntropyCoderIf->codeCrossComponentPrediction( rTu, compID ); +} + +/** encode motion information for every PU block + * \param pcCU + * \param uiAbsPartIdx + * \param bRD + * \returns Void + */ +Void TEncEntropy::encodePUWise( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + const Bool bDebugPred = bDebugPredEnabled && g_bFinalEncode; +#endif + + PartSize ePartSize = pcCU->getPartitionSize( uiAbsPartIdx ); + UInt uiNumPU = ( ePartSize == SIZE_2Nx2N ? 1 : ( ePartSize == SIZE_NxN ? 4 : 2 ) ); + UInt uiDepth = pcCU->getDepth( uiAbsPartIdx ); + UInt uiPUOffset = ( g_auiPUOffset[UInt( ePartSize )] << ( ( pcCU->getSlice()->getSPS()->getMaxCUDepth() - uiDepth ) << 1 ) ) >> 4; + + for ( UInt uiPartIdx = 0, uiSubPartIdx = uiAbsPartIdx; uiPartIdx < uiNumPU; uiPartIdx++, uiSubPartIdx += uiPUOffset ) + { + encodeMergeFlag( pcCU, uiSubPartIdx ); + if ( pcCU->getMergeFlag( uiSubPartIdx ) ) + { + encodeMergeIndex( pcCU, uiSubPartIdx ); +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (bDebugPred) + { + std::cout << "Coded merge flag, CU absPartIdx: " << uiAbsPartIdx << " PU(" << uiPartIdx << ") absPartIdx: " << uiSubPartIdx; + std::cout << " merge index: " << (UInt)pcCU->getMergeIndex(uiSubPartIdx) << std::endl; + } +#endif + } + else + { + encodeInterDirPU( pcCU, uiSubPartIdx ); + for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) + { + if ( pcCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 ) + { + encodeRefFrmIdxPU ( pcCU, uiSubPartIdx, RefPicList( uiRefListIdx ) ); + encodeMvdPU ( pcCU, uiSubPartIdx, RefPicList( uiRefListIdx ) ); + encodeMVPIdxPU ( pcCU, uiSubPartIdx, RefPicList( uiRefListIdx ) ); +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (bDebugPred) + { + std::cout << "refListIdx: " << uiRefListIdx << std::endl; + std::cout << "MVD horizontal: " << pcCU->getCUMvField(RefPicList(uiRefListIdx))->getMvd( uiAbsPartIdx ).getHor() << std::endl; + std::cout << "MVD vertical: " << pcCU->getCUMvField(RefPicList(uiRefListIdx))->getMvd( uiAbsPartIdx ).getVer() << std::endl; + std::cout << "MVPIdxPU: " << pcCU->getMVPIdx(RefPicList( uiRefListIdx ), uiSubPartIdx) << std::endl; + std::cout << "InterDir: " << (UInt)pcCU->getInterDir(uiSubPartIdx) << std::endl; + } +#endif + } + } + } + } + + return; +} + +Void TEncEntropy::encodeInterDirPU( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + if ( !pcCU->getSlice()->isInterB() ) + { + return; + } + + m_pcEntropyCoderIf->codeInterDir( pcCU, uiAbsPartIdx ); + + return; +} + +/** encode reference frame index for a PU block + * \param pcCU + * \param uiAbsPartIdx + * \param eRefList + * \returns Void + */ +Void TEncEntropy::encodeRefFrmIdxPU( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + assert( pcCU->isInter( uiAbsPartIdx ) ); + + if ( ( pcCU->getSlice()->getNumRefIdx( eRefList ) == 1 ) ) + { + return; + } + + if ( pcCU->getInterDir( uiAbsPartIdx ) & ( 1 << eRefList ) ) + { + m_pcEntropyCoderIf->codeRefFrmIdx( pcCU, uiAbsPartIdx, eRefList ); + } + + return; +} + +/** encode motion vector difference for a PU block + * \param pcCU + * \param uiAbsPartIdx + * \param eRefList + * \returns Void + */ +Void TEncEntropy::encodeMvdPU( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + assert( pcCU->isInter( uiAbsPartIdx ) ); + + if ( pcCU->getInterDir( uiAbsPartIdx ) & ( 1 << eRefList ) ) + { + m_pcEntropyCoderIf->codeMvd( pcCU, uiAbsPartIdx, eRefList ); + } + return; +} + +Void TEncEntropy::encodeMVPIdxPU( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + if ( (pcCU->getInterDir( uiAbsPartIdx ) & ( 1 << eRefList )) ) + { + m_pcEntropyCoderIf->codeMVPIdx( pcCU, uiAbsPartIdx, eRefList ); + } + + return; +} + +Void TEncEntropy::encodeQtCbf( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ) +{ + m_pcEntropyCoderIf->codeQtCbf( rTu, compID, lowestLevel ); +} + +Void TEncEntropy::encodeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ) +{ + m_pcEntropyCoderIf->codeTransformSubdivFlag( uiSymbol, uiCtx ); +} + +Void TEncEntropy::encodeQtRootCbf( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + m_pcEntropyCoderIf->codeQtRootCbf( pcCU, uiAbsPartIdx ); +} + +Void TEncEntropy::encodeQtCbfZero( TComTU &rTu, const ChannelType chType ) +{ + m_pcEntropyCoderIf->codeQtCbfZero( rTu, chType ); +} + +Void TEncEntropy::encodeQtRootCbfZero( TComDataCU* pcCU ) +{ + m_pcEntropyCoderIf->codeQtRootCbfZero( pcCU ); +} + +// dQP +Void TEncEntropy::encodeQP( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD ) +{ + if( bRD ) + { + uiAbsPartIdx = 0; + } + + if ( pcCU->getSlice()->getPPS()->getUseDQP() ) + { + m_pcEntropyCoderIf->codeDeltaQP( pcCU, uiAbsPartIdx ); + } +} + +/** encode chroma qp adjustment + * \returns Void + */ +Void TEncEntropy::encodeChromaQpAdjustment( TComDataCU* cu, UInt absPartIdx, Bool inRd ) +{ + if( inRd ) + { + absPartIdx = 0; + } + + m_pcEntropyCoderIf->codeChromaQpAdjustment( cu, absPartIdx ); +} + +// texture + +/** encode coefficients + * \param pcCU + * \param uiAbsPartIdx + * \param uiDepth + * \param uiWidth + * \param uiHeight + */ +Void TEncEntropy::encodeCoeff( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool& bCodeDQP, Bool& codeChromaQpAdj ) +{ +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + const Bool bDebugRQT=g_bFinalEncode && DebugOptionList::DebugRQT.getInt()!=0; +#endif + + if( pcCU->isIntra(uiAbsPartIdx) ) + { + if (false) + { + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tdecodeTransformIdx()\tCUDepth=" ) + DTRACE_CABAC_V( uiDepth ) + DTRACE_CABAC_T( "\n" ) + } + } + else + { + if( !(pcCU->getMergeFlag( uiAbsPartIdx ) && pcCU->getPartitionSize(uiAbsPartIdx) == SIZE_2Nx2N ) ) + { + m_pcEntropyCoderIf->codeQtRootCbf( pcCU, uiAbsPartIdx ); + } + if ( !pcCU->getQtRootCbf( uiAbsPartIdx ) ) + { + return; + } + } + + TComTURecurse tuRecurse(pcCU, uiAbsPartIdx, uiDepth); +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (bDebugRQT) printf("..codeCoeff: uiAbsPartIdx=%d, PU format=%d, 2Nx2N=%d, NxN=%d\n", uiAbsPartIdx, pcCU->getPartitionSize(uiAbsPartIdx), SIZE_2Nx2N, SIZE_NxN); +#endif + + xEncodeTransform( bCodeDQP, codeChromaQpAdj, tuRecurse ); +} + +Void TEncEntropy::encodeCoeffNxN( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID) +{ + TComDataCU *pcCU = rTu.getCU(); + + if (pcCU->getCbf(rTu.GetAbsPartIdxTU(), compID, rTu.GetTransformDepthRel()) != 0) + { + if (rTu.getRect(compID).width != rTu.getRect(compID).height) + { + //code two sub-TUs + TComTURecurse subTUIterator(rTu, false, TComTU::VERTICAL_SPLIT, true, compID); + + const UInt subTUSize = subTUIterator.getRect(compID).width * subTUIterator.getRect(compID).height; + + do + { + const UChar subTUCBF = pcCU->getCbf(subTUIterator.GetAbsPartIdxTU(compID), compID, (subTUIterator.GetTransformDepthRel() + 1)); + + if (subTUCBF != 0) + { + m_pcEntropyCoderIf->codeCoeffNxN( subTUIterator, (pcCoef + (subTUIterator.GetSectionNumber() * subTUSize)), compID); + } + } + while (subTUIterator.nextSection(rTu)); + } + else + { + m_pcEntropyCoderIf->codeCoeffNxN(rTu, pcCoef, compID); + } + } +} + +Void TEncEntropy::estimateBit (estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, const ChannelType chType) +{ + const UInt heightAtEntropyCoding = (width != height) ? (height >> 1) : height; + + m_pcEntropyCoderIf->estBit ( pcEstBitsSbac, width, heightAtEntropyCoding, chType ); +} + +Int TEncEntropy::countNonZeroCoeffs( TCoeff* pcCoef, UInt uiSize ) +{ + Int count = 0; + + for ( Int i = 0; i < uiSize; i++ ) + { + count += pcCoef[i] != 0; + } + + return count; +} + +/** encode quantization matrix + * \param scalingList quantization matrix information + */ +Void TEncEntropy::encodeScalingList( TComScalingList* scalingList ) +{ + m_pcEntropyCoderIf->codeScalingList( scalingList ); +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncEntropy.h b/jctvc/TLibEncoder/TEncEntropy.h new file mode 100644 index 0000000..0fff596 --- /dev/null +++ b/jctvc/TLibEncoder/TEncEntropy.h @@ -0,0 +1,193 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncEntropy.h + \brief entropy encoder class (header) +*/ + +#ifndef __TENCENTROPY__ +#define __TENCENTROPY__ + +#include "TLibCommon/TComSlice.h" +#include "TLibCommon/TComDataCU.h" +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/ContextModel.h" +#include "TLibCommon/TComPic.h" +#include "TLibCommon/TComTrQuant.h" +#include "TLibCommon/TComSampleAdaptiveOffset.h" +#include "TLibCommon/TComChromaFormat.h" + +class TEncSbac; +class TEncCavlc; +class SEI; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// entropy encoder pure class +class TEncEntropyIf +{ +public: + virtual Void resetEntropy () = 0; + virtual Void determineCabacInitIdx () = 0; + virtual Void setBitstream ( TComBitIf* p ) = 0; + virtual Void setSlice ( TComSlice* p ) = 0; + virtual Void resetBits () = 0; + virtual UInt getNumberOfWrittenBits() = 0; + + virtual Void codeVPS ( TComVPS* pcVPS ) = 0; + virtual Void codeSPS ( TComSPS* pcSPS ) = 0; + virtual Void codePPS ( TComPPS* pcPPS ) = 0; + virtual Void codeSliceHeader ( TComSlice* pcSlice ) = 0; + + virtual Void codeTilesWPPEntryPoint ( TComSlice* pSlice ) = 0; + virtual Void codeTerminatingBit ( UInt uilsLast ) = 0; + virtual Void codeSliceFinish () = 0; + virtual Void codeMVPIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) = 0; + virtual Void codeScalingList ( TComScalingList* scalingList ) = 0; + +public: + virtual Void codeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeSkipFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeMergeFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeMergeIndex ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0; + + virtual Void codePartSize ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0; + virtual Void codePredMode ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + + virtual Void codeIPCMInfo ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + + virtual Void codeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ) = 0; + virtual Void codeQtCbf ( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ) = 0; + virtual Void codeQtRootCbf ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeQtCbfZero ( TComTU &rTu, const ChannelType chType ) = 0; + virtual Void codeQtRootCbfZero ( TComDataCU* pcCU ) = 0; + virtual Void codeIntraDirLumaAng( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool isMultiplePU ) = 0; + + virtual Void codeIntraDirChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeInterDir ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeRefFrmIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) = 0; + virtual Void codeMvd ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) = 0; + + virtual Void codeCrossComponentPrediction( TComTU &rTu, ComponentID compID ) = 0; + + virtual Void codeDeltaQP ( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeChromaQpAdjustment( TComDataCU* pcCU, UInt uiAbsPartIdx ) = 0; + virtual Void codeCoeffNxN ( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID ) = 0; + virtual Void codeTransformSkipFlags ( TComTU &rTu, ComponentID component ) = 0; + virtual Void codeSAOBlkParam (SAOBlkParam& saoBlkParam, Bool* sliceEnabled, Bool leftMergeAvail, Bool aboveMergeAvail, Bool onlyEstMergeInfo = false) =0; + virtual Void estBit (estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType) = 0; + + virtual Void codeDFFlag (UInt uiCode, const Char *pSymbolName) = 0; + virtual Void codeDFSvlc (Int iCode, const Char *pSymbolName) = 0; + + virtual Void codeExplicitRdpcmMode ( TComTU &rTu, const ComponentID compID ) = 0; + + virtual ~TEncEntropyIf() {} +}; + +/// entropy encoder class +class TEncEntropy +{ +public: + Void setEntropyCoder ( TEncEntropyIf* e, TComSlice* pcSlice ); + Void setBitstream ( TComBitIf* p ) { m_pcEntropyCoderIf->setBitstream(p); } + Void resetBits () { m_pcEntropyCoderIf->resetBits(); } + UInt getNumberOfWrittenBits () { return m_pcEntropyCoderIf->getNumberOfWrittenBits(); } + Void resetEntropy () { m_pcEntropyCoderIf->resetEntropy(); } + Void determineCabacInitIdx () { m_pcEntropyCoderIf->determineCabacInitIdx(); } + + Void encodeSliceHeader ( TComSlice* pcSlice ); + Void encodeTilesWPPEntryPoint( TComSlice* pSlice ); + Void encodeTerminatingBit ( UInt uiIsLast ); + Void encodeSliceFinish (); + TEncEntropyIf* m_pcEntropyCoderIf; + +public: + Void encodeVPS ( TComVPS* pcVPS); + // SPS + Void encodeSPS ( TComSPS* pcSPS ); + Void encodePPS ( TComPPS* pcPPS ); + Void encodeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD = false ); + Void encodeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodeSkipFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodePUWise ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void encodeInterDirPU ( TComDataCU* pcSubCU, UInt uiAbsPartIdx ); + Void encodeRefFrmIdxPU ( TComDataCU* pcSubCU, UInt uiAbsPartIdx, RefPicList eRefList ); + Void encodeMvdPU ( TComDataCU* pcSubCU, UInt uiAbsPartIdx, RefPicList eRefList ); + Void encodeMVPIdxPU ( TComDataCU* pcSubCU, UInt uiAbsPartIdx, RefPicList eRefList ); + Void encodeMergeFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void encodeMergeIndex ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodePredMode ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodePartSize ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD = false ); + Void encodeIPCMInfo ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodePredInfo ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void encodeIntraDirModeLuma ( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiplePU = false ); + + Void encodeIntraDirModeChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ); + + Void encodeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ); + Void encodeQtCbf ( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ); + + Void encodeQtCbfZero ( TComTU &rTu, const ChannelType chType ); + Void encodeQtRootCbfZero ( TComDataCU* pcCU ); + Void encodeQtRootCbf ( TComDataCU* pcCU, UInt uiAbsPartIdx ); + Void encodeQP ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + Void encodeChromaQpAdjustment ( TComDataCU* pcCU, UInt uiAbsPartIdx, Bool bRD = false ); + + Void encodeScalingList ( TComScalingList* scalingList ); + + Void encodeCrossComponentPrediction( TComTU &rTu, ComponentID compID ); + +private: + Void xEncodeTransform ( Bool& bCodeDQP, Bool& codeChromaQpAdj, TComTU &rTu ); + +public: + Void encodeCoeff ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool& bCodeDQP, Bool& codeChromaQpAdj ); + + Void encodeCoeffNxN ( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID ); + + Void estimateBit ( estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType ); + + Void encodeSAOBlkParam(SAOBlkParam& saoBlkParam, Bool* sliceEnabled, Bool leftMergeAvail, Bool aboveMergeAvail){m_pcEntropyCoderIf->codeSAOBlkParam(saoBlkParam, sliceEnabled, leftMergeAvail, aboveMergeAvail, false);} + + static Int countNonZeroCoeffs( TCoeff* pcCoef, UInt uiSize ); + +};// END CLASS DEFINITION TEncEntropy + +//! \} + +#endif // __TENCENTROPY__ + diff --git a/jctvc/TLibEncoder/TEncGOP.cpp b/jctvc/TLibEncoder/TEncGOP.cpp new file mode 100644 index 0000000..a731f1d --- /dev/null +++ b/jctvc/TLibEncoder/TEncGOP.cpp @@ -0,0 +1,2837 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncGOP.cpp + \brief GOP encoder class +*/ + +#include +#include +#include + +#include "TEncTop.h" +#include "TEncGOP.h" +#include "TEncAnalyze.h" +#include "libmd5/MD5.h" +#include "TLibCommon/SEI.h" +#include "TLibCommon/NAL.h" +#include "NALwrite.h" +#include +#include + +#define VERBOSE_FRAME 0 + +using namespace std; + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST +Bool g_bFinalEncode = false; +#endif + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / initialization / destroy +// ==================================================================================================================== +Int getLSB(Int poc, Int maxLSB) +{ + if (poc >= 0) + { + return poc % maxLSB; + } + else + { + return (maxLSB - ((-poc) % maxLSB)) % maxLSB; + } +} + +TEncGOP::TEncGOP() +{ + m_iLastIDR = 0; + m_iGopSize = 0; + m_iNumPicCoded = 0; //Niko + m_bFirst = true; +#if ALLOW_RECOVERY_POINT_AS_RAP + m_iLastRecoveryPicPOC = 0; +#endif + + m_pcCfg = NULL; + m_pcSliceEncoder = NULL; + m_pcListPic = NULL; + + m_pcEntropyCoder = NULL; + m_pcCavlcCoder = NULL; + m_pcSbacCoder = NULL; + m_pcBinCABAC = NULL; + + m_bSeqFirst = true; + + m_bRefreshPending = 0; + m_pocCRA = 0; + m_numLongTermRefPicSPS = 0; + ::memset(m_ltRefPicPocLsbSps, 0, sizeof(m_ltRefPicPocLsbSps)); + ::memset(m_ltRefPicUsedByCurrPicFlag, 0, sizeof(m_ltRefPicUsedByCurrPicFlag)); + m_cpbRemovalDelay = 0; + m_lastBPSEI = 0; + xResetNonNestedSEIPresentFlags(); + xResetNestedSEIPresentFlags(); + m_associatedIRAPType = NAL_UNIT_CODED_SLICE_IDR_N_LP; + m_associatedIRAPPOC = 0; + return; +} + +TEncGOP::~TEncGOP() +{ +} + +/** Create list to contain pointers to CTU start addresses of slice. + */ +Void TEncGOP::create() +{ + m_bLongtermTestPictureHasBeenCoded = 0; + m_bLongtermTestPictureHasBeenCoded2 = 0; +} + +Void TEncGOP::destroy() +{ +} + +Void TEncGOP::init ( TEncTop* pcTEncTop ) +{ + m_pcEncTop = pcTEncTop; + m_pcCfg = pcTEncTop; + m_pcSliceEncoder = pcTEncTop->getSliceEncoder(); + m_pcListPic = pcTEncTop->getListPic(); + + m_pcEntropyCoder = pcTEncTop->getEntropyCoder(); + m_pcCavlcCoder = pcTEncTop->getCavlcCoder(); + m_pcSbacCoder = pcTEncTop->getSbacCoder(); + m_pcBinCABAC = pcTEncTop->getBinCABAC(); + m_pcLoopFilter = pcTEncTop->getLoopFilter(); + + m_pcSAO = pcTEncTop->getSAO(); + m_pcRateCtrl = pcTEncTop->getRateCtrl(); + m_lastBPSEI = 0; + m_totalCoded = 0; + +} + +SEIActiveParameterSets* TEncGOP::xCreateSEIActiveParameterSets (TComSPS *sps) +{ + SEIActiveParameterSets *seiActiveParameterSets = new SEIActiveParameterSets(); + seiActiveParameterSets->activeVPSId = m_pcCfg->getVPS()->getVPSId(); + seiActiveParameterSets->m_selfContainedCvsFlag = false; + seiActiveParameterSets->m_noParameterSetUpdateFlag = false; + seiActiveParameterSets->numSpsIdsMinus1 = 0; + seiActiveParameterSets->activeSeqParameterSetId.resize(seiActiveParameterSets->numSpsIdsMinus1 + 1); + seiActiveParameterSets->activeSeqParameterSetId[0] = sps->getSPSId(); + return seiActiveParameterSets; +} + +SEIFramePacking* TEncGOP::xCreateSEIFramePacking() +{ + SEIFramePacking *seiFramePacking = new SEIFramePacking(); + seiFramePacking->m_arrangementId = m_pcCfg->getFramePackingArrangementSEIId(); + seiFramePacking->m_arrangementCancelFlag = 0; + seiFramePacking->m_arrangementType = m_pcCfg->getFramePackingArrangementSEIType(); + assert((seiFramePacking->m_arrangementType > 2) && (seiFramePacking->m_arrangementType < 6) ); + seiFramePacking->m_quincunxSamplingFlag = m_pcCfg->getFramePackingArrangementSEIQuincunx(); + seiFramePacking->m_contentInterpretationType = m_pcCfg->getFramePackingArrangementSEIInterpretation(); + seiFramePacking->m_spatialFlippingFlag = 0; + seiFramePacking->m_frame0FlippedFlag = 0; + seiFramePacking->m_fieldViewsFlag = (seiFramePacking->m_arrangementType == 2); + seiFramePacking->m_currentFrameIsFrame0Flag = ((seiFramePacking->m_arrangementType == 5) && (m_iNumPicCoded&1)); + seiFramePacking->m_frame0SelfContainedFlag = 0; + seiFramePacking->m_frame1SelfContainedFlag = 0; + seiFramePacking->m_frame0GridPositionX = 0; + seiFramePacking->m_frame0GridPositionY = 0; + seiFramePacking->m_frame1GridPositionX = 0; + seiFramePacking->m_frame1GridPositionY = 0; + seiFramePacking->m_arrangementReservedByte = 0; + seiFramePacking->m_arrangementPersistenceFlag = true; + seiFramePacking->m_upsampledAspectRatio = 0; + return seiFramePacking; +} + +SEISegmentedRectFramePacking* TEncGOP::xCreateSEISegmentedRectFramePacking() +{ + SEISegmentedRectFramePacking *seiSegmentedRectFramePacking = new SEISegmentedRectFramePacking(); + seiSegmentedRectFramePacking->m_arrangementCancelFlag = m_pcCfg->getSegmentedRectFramePackingArrangementSEICancel(); + seiSegmentedRectFramePacking->m_contentInterpretationType = m_pcCfg->getSegmentedRectFramePackingArrangementSEIType(); + seiSegmentedRectFramePacking->m_arrangementPersistenceFlag = m_pcCfg->getSegmentedRectFramePackingArrangementSEIPersistence(); + return seiSegmentedRectFramePacking; +} + +SEIDisplayOrientation* TEncGOP::xCreateSEIDisplayOrientation() +{ + SEIDisplayOrientation *seiDisplayOrientation = new SEIDisplayOrientation(); + seiDisplayOrientation->cancelFlag = false; + seiDisplayOrientation->horFlip = false; + seiDisplayOrientation->verFlip = false; + seiDisplayOrientation->anticlockwiseRotation = m_pcCfg->getDisplayOrientationSEIAngle(); + return seiDisplayOrientation; +} +SEIToneMappingInfo* TEncGOP::xCreateSEIToneMappingInfo() +{ + SEIToneMappingInfo *seiToneMappingInfo = new SEIToneMappingInfo(); + seiToneMappingInfo->m_toneMapId = m_pcCfg->getTMISEIToneMapId(); + seiToneMappingInfo->m_toneMapCancelFlag = m_pcCfg->getTMISEIToneMapCancelFlag(); + seiToneMappingInfo->m_toneMapPersistenceFlag = m_pcCfg->getTMISEIToneMapPersistenceFlag(); + + seiToneMappingInfo->m_codedDataBitDepth = m_pcCfg->getTMISEICodedDataBitDepth(); + assert(seiToneMappingInfo->m_codedDataBitDepth >= 8 && seiToneMappingInfo->m_codedDataBitDepth <= 14); + seiToneMappingInfo->m_targetBitDepth = m_pcCfg->getTMISEITargetBitDepth(); + assert(seiToneMappingInfo->m_targetBitDepth >= 1 && seiToneMappingInfo->m_targetBitDepth <= 17); + seiToneMappingInfo->m_modelId = m_pcCfg->getTMISEIModelID(); + assert(seiToneMappingInfo->m_modelId >=0 &&seiToneMappingInfo->m_modelId<=4); + + switch( seiToneMappingInfo->m_modelId) + { + case 0: + { + seiToneMappingInfo->m_minValue = m_pcCfg->getTMISEIMinValue(); + seiToneMappingInfo->m_maxValue = m_pcCfg->getTMISEIMaxValue(); + break; + } + case 1: + { + seiToneMappingInfo->m_sigmoidMidpoint = m_pcCfg->getTMISEISigmoidMidpoint(); + seiToneMappingInfo->m_sigmoidWidth = m_pcCfg->getTMISEISigmoidWidth(); + break; + } + case 2: + { + UInt num = 1u<<(seiToneMappingInfo->m_targetBitDepth); + seiToneMappingInfo->m_startOfCodedInterval.resize(num); + Int* ptmp = m_pcCfg->getTMISEIStartOfCodedInterva(); + if(ptmp) + { + for(Int i=0; im_startOfCodedInterval[i] = ptmp[i]; + } + } + break; + } + case 3: + { + seiToneMappingInfo->m_numPivots = m_pcCfg->getTMISEINumPivots(); + seiToneMappingInfo->m_codedPivotValue.resize(seiToneMappingInfo->m_numPivots); + seiToneMappingInfo->m_targetPivotValue.resize(seiToneMappingInfo->m_numPivots); + Int* ptmpcoded = m_pcCfg->getTMISEICodedPivotValue(); + Int* ptmptarget = m_pcCfg->getTMISEITargetPivotValue(); + if(ptmpcoded&&ptmptarget) + { + for(Int i=0; i<(seiToneMappingInfo->m_numPivots);i++) + { + seiToneMappingInfo->m_codedPivotValue[i]=ptmpcoded[i]; + seiToneMappingInfo->m_targetPivotValue[i]=ptmptarget[i]; + } + } + break; + } + case 4: + { + seiToneMappingInfo->m_cameraIsoSpeedIdc = m_pcCfg->getTMISEICameraIsoSpeedIdc(); + seiToneMappingInfo->m_cameraIsoSpeedValue = m_pcCfg->getTMISEICameraIsoSpeedValue(); + assert( seiToneMappingInfo->m_cameraIsoSpeedValue !=0 ); + seiToneMappingInfo->m_exposureIndexIdc = m_pcCfg->getTMISEIExposurIndexIdc(); + seiToneMappingInfo->m_exposureIndexValue = m_pcCfg->getTMISEIExposurIndexValue(); + assert( seiToneMappingInfo->m_exposureIndexValue !=0 ); + seiToneMappingInfo->m_exposureCompensationValueSignFlag = m_pcCfg->getTMISEIExposureCompensationValueSignFlag(); + seiToneMappingInfo->m_exposureCompensationValueNumerator = m_pcCfg->getTMISEIExposureCompensationValueNumerator(); + seiToneMappingInfo->m_exposureCompensationValueDenomIdc = m_pcCfg->getTMISEIExposureCompensationValueDenomIdc(); + seiToneMappingInfo->m_refScreenLuminanceWhite = m_pcCfg->getTMISEIRefScreenLuminanceWhite(); + seiToneMappingInfo->m_extendedRangeWhiteLevel = m_pcCfg->getTMISEIExtendedRangeWhiteLevel(); + assert( seiToneMappingInfo->m_extendedRangeWhiteLevel >= 100 ); + seiToneMappingInfo->m_nominalBlackLevelLumaCodeValue = m_pcCfg->getTMISEINominalBlackLevelLumaCodeValue(); + seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue = m_pcCfg->getTMISEINominalWhiteLevelLumaCodeValue(); + assert( seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue > seiToneMappingInfo->m_nominalBlackLevelLumaCodeValue ); + seiToneMappingInfo->m_extendedWhiteLevelLumaCodeValue = m_pcCfg->getTMISEIExtendedWhiteLevelLumaCodeValue(); + assert( seiToneMappingInfo->m_extendedWhiteLevelLumaCodeValue >= seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue ); + break; + } + default: + { + assert(!"Undefined SEIToneMapModelId"); + break; + } + } + return seiToneMappingInfo; +} + +SEITempMotionConstrainedTileSets* TEncGOP::xCreateSEITempMotionConstrainedTileSets () +{ + TComPPS *pps = m_pcEncTop->getPPS(); + SEITempMotionConstrainedTileSets *sei = new SEITempMotionConstrainedTileSets(); + if(pps->getTilesEnabledFlag()) + { + sei->m_mc_all_tiles_exact_sample_value_match_flag = false; + sei->m_each_tile_one_tile_set_flag = false; + sei->m_limited_tile_set_display_flag = false; + sei->setNumberOfTileSets((pps->getNumTileColumnsMinus1() + 1) * (pps->getNumTileRowsMinus1() + 1)); + + for(Int i=0; i < sei->getNumberOfTileSets(); i++) + { + sei->tileSetData(i).m_mcts_id = i; //depends the application; + sei->tileSetData(i).setNumberOfTileRects(1); + + for(Int j=0; jtileSetData(i).getNumberOfTileRects(); j++) + { + sei->tileSetData(i).topLeftTileIndex(j) = i+j; + sei->tileSetData(i).bottomRightTileIndex(j) = i+j; + } + + sei->tileSetData(i).m_exact_sample_value_match_flag = false; + sei->tileSetData(i).m_mcts_tier_level_idc_present_flag = false; + } + } + else + { + assert(!"Tile is not enabled"); + } + return sei; +} + +SEIKneeFunctionInfo* TEncGOP::xCreateSEIKneeFunctionInfo() +{ + SEIKneeFunctionInfo *seiKneeFunctionInfo = new SEIKneeFunctionInfo(); + seiKneeFunctionInfo->m_kneeId = m_pcCfg->getKneeSEIId(); + seiKneeFunctionInfo->m_kneeCancelFlag = m_pcCfg->getKneeSEICancelFlag(); + if ( !seiKneeFunctionInfo->m_kneeCancelFlag ) + { + seiKneeFunctionInfo->m_kneePersistenceFlag = m_pcCfg->getKneeSEIPersistenceFlag(); + seiKneeFunctionInfo->m_kneeInputDrange = m_pcCfg->getKneeSEIInputDrange(); + seiKneeFunctionInfo->m_kneeInputDispLuminance = m_pcCfg->getKneeSEIInputDispLuminance(); + seiKneeFunctionInfo->m_kneeOutputDrange = m_pcCfg->getKneeSEIOutputDrange(); + seiKneeFunctionInfo->m_kneeOutputDispLuminance = m_pcCfg->getKneeSEIOutputDispLuminance(); + + seiKneeFunctionInfo->m_kneeNumKneePointsMinus1 = m_pcCfg->getKneeSEINumKneePointsMinus1(); + Int* piInputKneePoint = m_pcCfg->getKneeSEIInputKneePoint(); + Int* piOutputKneePoint = m_pcCfg->getKneeSEIOutputKneePoint(); + if(piInputKneePoint&&piOutputKneePoint) + { + seiKneeFunctionInfo->m_kneeInputKneePoint.resize(seiKneeFunctionInfo->m_kneeNumKneePointsMinus1+1); + seiKneeFunctionInfo->m_kneeOutputKneePoint.resize(seiKneeFunctionInfo->m_kneeNumKneePointsMinus1+1); + for(Int i=0; i<=seiKneeFunctionInfo->m_kneeNumKneePointsMinus1; i++) + { + seiKneeFunctionInfo->m_kneeInputKneePoint[i] = piInputKneePoint[i]; + seiKneeFunctionInfo->m_kneeOutputKneePoint[i] = piOutputKneePoint[i]; + } + } + } + return seiKneeFunctionInfo; +} + +SEIChromaSamplingFilterHint* TEncGOP::xCreateSEIChromaSamplingFilterHint(Bool bChromaLocInfoPresent, Int iHorFilterIndex, Int iVerFilterIndex) +{ + SEIChromaSamplingFilterHint *seiChromaSamplingFilterHint = new SEIChromaSamplingFilterHint(); + seiChromaSamplingFilterHint->m_verChromaFilterIdc = iVerFilterIndex; + seiChromaSamplingFilterHint->m_horChromaFilterIdc = iHorFilterIndex; + seiChromaSamplingFilterHint->m_verFilteringProcessFlag = 1; + seiChromaSamplingFilterHint->m_targetFormatIdc = 3; + seiChromaSamplingFilterHint->m_perfectReconstructionFlag = false; + if(seiChromaSamplingFilterHint->m_verChromaFilterIdc == 1) + { + seiChromaSamplingFilterHint->m_numVerticalFilters = 1; + seiChromaSamplingFilterHint->m_verTapLengthMinus1 = (Int*)malloc(seiChromaSamplingFilterHint->m_numVerticalFilters * sizeof(Int)); + seiChromaSamplingFilterHint->m_verFilterCoeff = (Int**)malloc(seiChromaSamplingFilterHint->m_numVerticalFilters * sizeof(Int*)); + for(Int i = 0; i < seiChromaSamplingFilterHint->m_numVerticalFilters; i ++) + { + seiChromaSamplingFilterHint->m_verTapLengthMinus1[i] = 0; + seiChromaSamplingFilterHint->m_verFilterCoeff[i] = (Int*)malloc(seiChromaSamplingFilterHint->m_verTapLengthMinus1[i] * sizeof(Int)); + for(Int j = 0; j < seiChromaSamplingFilterHint->m_verTapLengthMinus1[i]; j ++) + { + seiChromaSamplingFilterHint->m_verFilterCoeff[i][j] = 0; + } + } + } + else + { + seiChromaSamplingFilterHint->m_numVerticalFilters = 0; + seiChromaSamplingFilterHint->m_verTapLengthMinus1 = NULL; + seiChromaSamplingFilterHint->m_verFilterCoeff = NULL; + } + if(seiChromaSamplingFilterHint->m_horChromaFilterIdc == 1) + { + seiChromaSamplingFilterHint->m_numHorizontalFilters = 1; + seiChromaSamplingFilterHint->m_horTapLengthMinus1 = (Int*)malloc(seiChromaSamplingFilterHint->m_numHorizontalFilters * sizeof(Int)); + seiChromaSamplingFilterHint->m_horFilterCoeff = (Int**)malloc(seiChromaSamplingFilterHint->m_numHorizontalFilters * sizeof(Int*)); + for(Int i = 0; i < seiChromaSamplingFilterHint->m_numHorizontalFilters; i ++) + { + seiChromaSamplingFilterHint->m_horTapLengthMinus1[i] = 0; + seiChromaSamplingFilterHint->m_horFilterCoeff[i] = (Int*)malloc(seiChromaSamplingFilterHint->m_horTapLengthMinus1[i] * sizeof(Int)); + for(Int j = 0; j < seiChromaSamplingFilterHint->m_horTapLengthMinus1[i]; j ++) + { + seiChromaSamplingFilterHint->m_horFilterCoeff[i][j] = 0; + } + } + } + else + { + seiChromaSamplingFilterHint->m_numHorizontalFilters = 0; + seiChromaSamplingFilterHint->m_horTapLengthMinus1 = NULL; + seiChromaSamplingFilterHint->m_horFilterCoeff = NULL; + } + return seiChromaSamplingFilterHint; +} + +Void TEncGOP::xCreateLeadingSEIMessages (/*SEIMessages seiMessages,*/ AccessUnit &accessUnit, TComSPS *sps) +{ + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + + if(m_pcCfg->getActiveParameterSetsSEIEnabled()) + { + SEIActiveParameterSets *sei = xCreateSEIActiveParameterSets (sps); + + //nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + m_activeParameterSetSEIPresentInAU = true; + } + + if(m_pcCfg->getFramePackingArrangementSEIEnabled()) + { + SEIFramePacking *sei = xCreateSEIFramePacking (); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + } + if(m_pcCfg->getSegmentedRectFramePackingArrangementSEIEnabled()) + { + SEISegmentedRectFramePacking *sei = xCreateSEISegmentedRectFramePacking (); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + } + if (m_pcCfg->getDisplayOrientationSEIAngle()) + { + SEIDisplayOrientation *sei = xCreateSEIDisplayOrientation(); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + } + + if(m_pcCfg->getToneMappingInfoSEIEnabled()) + { + SEIToneMappingInfo *sei = xCreateSEIToneMappingInfo (); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + } + + if(m_pcCfg->getTMCTSSEIEnabled()) + { + SEITempMotionConstrainedTileSets *sei_tmcts = xCreateSEITempMotionConstrainedTileSets (); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei_tmcts, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei_tmcts; + } + + if(m_pcCfg->getTimeCodeSEIEnabled()) + { + SEITimeCode sei_time_code; + // Set data as per command line options + sei_time_code.numClockTs = m_pcCfg->getNumberOfTimesets(); + for(Int i = 0; i < sei_time_code.numClockTs; i++) + sei_time_code.timeSetArray[i] = m_pcCfg->getTimeSet(i); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, sei_time_code, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + } + + if(m_pcCfg->getKneeSEIEnabled()) + { + SEIKneeFunctionInfo *sei = xCreateSEIKneeFunctionInfo(); + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + delete sei; + } + + if(m_pcCfg->getMasteringDisplaySEI().colourVolumeSEIEnabled) + { + const TComSEIMasteringDisplay &seiCfg=m_pcCfg->getMasteringDisplaySEI(); + SEIMasteringDisplayColourVolume mdcv; + mdcv.values = seiCfg; + + nalu = NALUnit(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, mdcv, sps); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + + } +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== +Void TEncGOP::compressGOP( Int iPOCLast, Int iNumPicRcvd, TComList& rcListPic, + TComList& rcListPicYuvRecOut, std::list& accessUnitsInGOP, + Bool isField, Bool isTff, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE ) +{ + // TODO: Split this function up. + + TComPic* pcPic = NULL; + TComPicYuv* pcPicYuvRecOut; + TComSlice* pcSlice; + TComOutputBitstream *pcBitstreamRedirect; + pcBitstreamRedirect = new TComOutputBitstream; + AccessUnit::iterator itLocationToPushSliceHeaderNALU; // used to store location where NALU containing slice header is to be inserted + + xInitGOP( iPOCLast, iNumPicRcvd, rcListPic, rcListPicYuvRecOut, isField ); + + m_iNumPicCoded = 0; + SEIPictureTiming pictureTimingSEI; + Bool writeSOP = m_pcCfg->getSOPDescriptionSEIEnabled(); + + // Initialize Scalable Nesting SEI with single layer values + SEIScalableNesting scalableNestingSEI; + scalableNestingSEI.m_bitStreamSubsetFlag = 1; // If the nested SEI messages are picture buffereing SEI mesages, picure timing SEI messages or sub-picture timing SEI messages, bitstream_subset_flag shall be equal to 1 + scalableNestingSEI.m_nestingOpFlag = 0; + scalableNestingSEI.m_nestingNumOpsMinus1 = 0; //nesting_num_ops_minus1 + scalableNestingSEI.m_allLayersFlag = 0; + scalableNestingSEI.m_nestingNoOpMaxTemporalIdPlus1 = 6 + 1; //nesting_no_op_max_temporal_id_plus1 + scalableNestingSEI.m_nestingNumLayersMinus1 = 1 - 1; //nesting_num_layers_minus1 + scalableNestingSEI.m_nestingLayerId[0] = 0; + scalableNestingSEI.m_callerOwnsSEIs = true; + + Int picSptDpbOutputDuDelay = 0; + UInt *accumBitsDU = NULL; + UInt *accumNalsDU = NULL; + SEIDecodingUnitInfo decodingUnitInfoSEI; + +#if EFFICIENT_FIELD_IRAP + Int IRAPGOPid = -1; + Bool IRAPtoReorder = false; + Bool swapIRAPForward = false; + if(isField) + { + Int pocCurr; + for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ ) + { + // determine actual POC + if(iPOCLast == 0) //case first frame or first top field + { + pocCurr=0; + } + else if(iPOCLast == 1 && isField) //case first bottom field, just like the first frame, the poc computation is not right anymore, we set the right value + { + pocCurr = 1; + } + else + { + pocCurr = iPOCLast - iNumPicRcvd + m_pcCfg->getGOPEntry(iGOPid).m_POC - isField; + } + + // check if POC corresponds to IRAP + NalUnitType tmpUnitType = getNalUnitType(pocCurr, m_iLastIDR, isField); + if(tmpUnitType >= NAL_UNIT_CODED_SLICE_BLA_W_LP && tmpUnitType <= NAL_UNIT_CODED_SLICE_CRA) // if picture is an IRAP + { + if(pocCurr%2 == 0 && iGOPid < m_iGopSize-1 && m_pcCfg->getGOPEntry(iGOPid).m_POC == m_pcCfg->getGOPEntry(iGOPid+1).m_POC-1) + { // if top field and following picture in enc order is associated bottom field + IRAPGOPid = iGOPid; + IRAPtoReorder = true; + swapIRAPForward = true; + break; + } + if(pocCurr%2 != 0 && iGOPid > 0 && m_pcCfg->getGOPEntry(iGOPid).m_POC == m_pcCfg->getGOPEntry(iGOPid-1).m_POC+1) + { + // if picture is an IRAP remember to process it first + IRAPGOPid = iGOPid; + IRAPtoReorder = true; + swapIRAPForward = false; + break; + } + } + } + } +#endif + // reset flag indicating whether pictures have been encoded + for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ ) + { + m_pcCfg->setEncodedFlag(iGOPid, false); + } + + for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ ) + { +#if EFFICIENT_FIELD_IRAP + if(IRAPtoReorder) + { + if(swapIRAPForward) + { + if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid +1; + } + else if(iGOPid == IRAPGOPid +1) + { + iGOPid = IRAPGOPid; + } + } + else + { + if(iGOPid == IRAPGOPid -1) + { + iGOPid = IRAPGOPid; + } + else if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid -1; + } + } + } +#endif + + UInt uiColDir = 1; + //-- For time output for each slice + clock_t iBeforeTime = clock(); + + //select uiColDir + Int iCloseLeft=1, iCloseRight=-1; + for(Int i = 0; igetGOPEntry(iGOPid).m_numRefPics; i++) + { + Int iRef = m_pcCfg->getGOPEntry(iGOPid).m_referencePics[i]; + if(iRef>0&&(iRefiCloseLeft||iCloseLeft==1)) + { + iCloseLeft=iRef; + } + } + if(iCloseRight>-1) + { + iCloseRight=iCloseRight+m_pcCfg->getGOPEntry(iGOPid).m_POC-1; + } + if(iCloseLeft<1) + { + iCloseLeft=iCloseLeft+m_pcCfg->getGOPEntry(iGOPid).m_POC-1; + while(iCloseLeft<0) + { + iCloseLeft+=m_iGopSize; + } + } + Int iLeftQP=0, iRightQP=0; + for(Int i=0; igetGOPEntry(i).m_POC==(iCloseLeft%m_iGopSize)+1) + { + iLeftQP= m_pcCfg->getGOPEntry(i).m_QPOffset; + } + if (m_pcCfg->getGOPEntry(i).m_POC==(iCloseRight%m_iGopSize)+1) + { + iRightQP=m_pcCfg->getGOPEntry(i).m_QPOffset; + } + } + if(iCloseRight>-1&&iRightQPgetGOPEntry(iGOPid).m_POC - ((isField && m_iGopSize>1) ? 1:0); + iTimeOffset = m_pcCfg->getGOPEntry(iGOPid).m_POC; + } + + if(pocCurr>=m_pcCfg->getFramesToBeEncoded()) + { +#if EFFICIENT_FIELD_IRAP + if(IRAPtoReorder) + { + if(swapIRAPForward) + { + if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid +1; + IRAPtoReorder = false; + } + else if(iGOPid == IRAPGOPid +1) + { + iGOPid --; + } + } + else + { + if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid -1; + } + else if(iGOPid == IRAPGOPid -1) + { + iGOPid = IRAPGOPid; + IRAPtoReorder = false; + } + } + } +#endif + continue; + } + + if( getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_N_LP ) + { + m_iLastIDR = pocCurr; + } + // start a new access unit: create an entry in the list of output access units + accessUnitsInGOP.push_back(AccessUnit()); + AccessUnit& accessUnit = accessUnitsInGOP.back(); + xGetBuffer( rcListPic, rcListPicYuvRecOut, iNumPicRcvd, iTimeOffset, pcPic, pcPicYuvRecOut, pocCurr, isField ); + + // Slice data initialization + pcPic->clearSliceBuffer(); + assert(pcPic->getNumAllocatedSlice() == 1); + m_pcSliceEncoder->setSliceIdx(0); + pcPic->setCurrSliceIdx(0); + + m_pcSliceEncoder->initEncSlice ( pcPic, iPOCLast, pocCurr, iNumPicRcvd, iGOPid, pcSlice, m_pcEncTop->getSPS(), m_pcEncTop->getPPS(), isField ); + + //Set Frame/Field coding + pcSlice->getPic()->setField(isField); + + pcSlice->setLastIDR(m_iLastIDR); + pcSlice->setSliceIdx(0); + //set default slice level flag to the same as SPS level flag + pcSlice->setLFCrossSliceBoundaryFlag( pcSlice->getPPS()->getLoopFilterAcrossSlicesEnabledFlag() ); + pcSlice->setScalingList ( m_pcEncTop->getScalingList() ); + if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_OFF) + { + m_pcEncTop->getTrQuant()->setFlatScalingList(pcSlice->getSPS()->getChromaFormatIdc()); + m_pcEncTop->getTrQuant()->setUseScalingList(false); + m_pcEncTop->getSPS()->setScalingListPresentFlag(false); + m_pcEncTop->getPPS()->setScalingListPresentFlag(false); + } + else if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_DEFAULT) + { + pcSlice->setDefaultScalingList (); + m_pcEncTop->getSPS()->setScalingListPresentFlag(false); + m_pcEncTop->getPPS()->setScalingListPresentFlag(false); + m_pcEncTop->getTrQuant()->setScalingList(pcSlice->getScalingList(), pcSlice->getSPS()->getChromaFormatIdc()); + m_pcEncTop->getTrQuant()->setUseScalingList(true); + } + else if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_FILE_READ) + { + pcSlice->setDefaultScalingList (); + if(pcSlice->getScalingList()->xParseScalingList(m_pcCfg->getScalingListFile())) + { + Bool bParsedScalingList=false; // Use of boolean so that assertion outputs useful string + assert(bParsedScalingList); + exit(1); + } + pcSlice->getScalingList()->checkDcOfMatrix(); + m_pcEncTop->getSPS()->setScalingListPresentFlag(pcSlice->checkDefaultScalingList()); + m_pcEncTop->getPPS()->setScalingListPresentFlag(false); + m_pcEncTop->getTrQuant()->setScalingList(pcSlice->getScalingList(), pcSlice->getSPS()->getChromaFormatIdc()); + m_pcEncTop->getTrQuant()->setUseScalingList(true); + } + else + { + printf("error : ScalingList == %d no support\n",m_pcEncTop->getUseScalingListId()); + assert(0); + } + + if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='P') + { + pcSlice->setSliceType(P_SLICE); + } + if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='I') + { + pcSlice->setSliceType(I_SLICE); + } + + // Set the nal unit type + pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField)); + if(pcSlice->getTemporalLayerNonReferenceFlag()) + { + if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_TRAIL_R && + !(m_iGopSize == 1 && pcSlice->getSliceType() == I_SLICE)) + // Add this condition to avoid POC issues with encoder_intra_main.cfg configuration (see #1127 in bug tracker) + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TRAIL_N); + } + if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RADL_R) + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RADL_N); + } + if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RASL_R) + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RASL_N); + } + } + +#if EFFICIENT_FIELD_IRAP + if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) // IRAP picture + { + m_associatedIRAPType = pcSlice->getNalUnitType(); + m_associatedIRAPPOC = pocCurr; + } + pcSlice->setAssociatedIRAPType(m_associatedIRAPType); + pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC); +#endif + // Do decoding refresh marking if any + pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic); + m_pcEncTop->selectReferencePictureSet(pcSlice, pocCurr, iGOPid); + pcSlice->getRPS()->setNumberOfLongtermPictures(0); +#if !EFFICIENT_FIELD_IRAP + if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) // IRAP picture + { + m_associatedIRAPType = pcSlice->getNalUnitType(); + m_associatedIRAPPOC = pocCurr; + } + pcSlice->setAssociatedIRAPType(m_associatedIRAPType); + pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC); +#endif + +#if ALLOW_RECOVERY_POINT_AS_RAP + if ((pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPS(), false, m_iLastRecoveryPicPOC, m_pcCfg->getDecodingRefreshType() == 3) != 0) || (pcSlice->isIRAP()) +#if EFFICIENT_FIELD_IRAP + || (isField && pcSlice->getAssociatedIRAPType() >= NAL_UNIT_CODED_SLICE_BLA_W_LP && pcSlice->getAssociatedIRAPType() <= NAL_UNIT_CODED_SLICE_CRA && pcSlice->getAssociatedIRAPPOC() == pcSlice->getPOC()+1) +#endif + ) + { + pcSlice->createExplicitReferencePictureSetFromReference(rcListPic, pcSlice->getRPS(), pcSlice->isIRAP(), m_iLastRecoveryPicPOC, m_pcCfg->getDecodingRefreshType() == 3); + } +#else + if ((pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPS(), false) != 0) || (pcSlice->isIRAP())) + { + pcSlice->createExplicitReferencePictureSetFromReference(rcListPic, pcSlice->getRPS(), pcSlice->isIRAP()); + } +#endif + + pcSlice->applyReferencePictureSet(rcListPic, pcSlice->getRPS()); + + if(pcSlice->getTLayer() > 0 + && !( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_N // Check if not a leading picture + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_R + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL_N + || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL_R ) + ) + { + if(pcSlice->isTemporalLayerSwitchingPoint(rcListPic) || pcSlice->getSPS()->getTemporalIdNestingFlag()) + { + if(pcSlice->getTemporalLayerNonReferenceFlag()) + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TSA_N); + } + else + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TSA_R); + } + } + else if(pcSlice->isStepwiseTemporalLayerSwitchingPointCandidate(rcListPic)) + { + Bool isSTSA=true; + for(Int ii=iGOPid+1;(iigetGOPSize() && isSTSA==true);ii++) + { + Int lTid= m_pcCfg->getGOPEntry(ii).m_temporalId; + if(lTid==pcSlice->getTLayer()) + { + TComReferencePictureSet* nRPS = pcSlice->getSPS()->getRPSList()->getReferencePictureSet(ii); + for(Int jj=0;jjgetNumberOfPictures();jj++) + { + if(nRPS->getUsed(jj)) + { + Int tPoc=m_pcCfg->getGOPEntry(ii).m_POC+nRPS->getDeltaPOC(jj); + Int kk=0; + for(kk=0;kkgetGOPSize();kk++) + { + if(m_pcCfg->getGOPEntry(kk).m_POC==tPoc) + break; + } + Int tTid=m_pcCfg->getGOPEntry(kk).m_temporalId; + if(tTid >= pcSlice->getTLayer()) + { + isSTSA=false; + break; + } + } + } + } + } + if(isSTSA==true) + { + if(pcSlice->getTemporalLayerNonReferenceFlag()) + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA_N); + } + else + { + pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA_R); + } + } + } + } + arrangeLongtermPicturesInRPS(pcSlice, rcListPic); + TComRefPicListModification* refPicListModification = pcSlice->getRefPicListModification(); + refPicListModification->setRefPicListModificationFlagL0(0); + refPicListModification->setRefPicListModificationFlagL1(0); + pcSlice->setNumRefIdx(REF_PIC_LIST_0,min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive,pcSlice->getRPS()->getNumberOfPictures())); + pcSlice->setNumRefIdx(REF_PIC_LIST_1,min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive,pcSlice->getRPS()->getNumberOfPictures())); + +#if ADAPTIVE_QP_SELECTION + pcSlice->setTrQuant( m_pcEncTop->getTrQuant() ); +#endif + + // Set reference list + pcSlice->setRefPicList ( rcListPic ); + + // Slice info. refinement + if ( (pcSlice->getSliceType() == B_SLICE) && (pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) ) + { + pcSlice->setSliceType ( P_SLICE ); + } + + if (pcSlice->getSliceType() == B_SLICE) + { + pcSlice->setColFromL0Flag(1-uiColDir); + Bool bLowDelay = true; + Int iCurrPOC = pcSlice->getPOC(); + Int iRefIdx = 0; + + for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++) + { + if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC ) + { + bLowDelay = false; + } + } + for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++) + { + if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC ) + { + bLowDelay = false; + } + } + + pcSlice->setCheckLDC(bLowDelay); + } + else + { + pcSlice->setCheckLDC(true); + } + + uiColDir = 1-uiColDir; + + //------------------------------------------------------------- + pcSlice->setRefPOCList(); + + pcSlice->setList1IdxToList0Idx(); + + if (m_pcEncTop->getTMVPModeId() == 2) + { + if (iGOPid == 0) // first picture in SOP (i.e. forward B) + { + pcSlice->setEnableTMVPFlag(0); + } + else + { + // Note: pcSlice->getColFromL0Flag() is assumed to be always 0 and getcolRefIdx() is always 0. + pcSlice->setEnableTMVPFlag(1); + } + pcSlice->getSPS()->setTMVPFlagsPresent(1); + } + else if (m_pcEncTop->getTMVPModeId() == 1) + { + pcSlice->getSPS()->setTMVPFlagsPresent(1); + pcSlice->setEnableTMVPFlag(1); + } + else + { + pcSlice->getSPS()->setTMVPFlagsPresent(0); + pcSlice->setEnableTMVPFlag(0); + } + /////////////////////////////////////////////////////////////////////////////////////////////////// Compress a slice + // Slice compression + if (m_pcCfg->getUseASR()) + { + m_pcSliceEncoder->setSearchRange(pcSlice); + } + + Bool bGPBcheck=false; + if ( pcSlice->getSliceType() == B_SLICE) + { + if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) ) + { + bGPBcheck=true; + Int i; + for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ ) + { + if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) ) + { + bGPBcheck=false; + break; + } + } + } + } + if(bGPBcheck) + { + pcSlice->setMvdL1ZeroFlag(true); + } + else + { + pcSlice->setMvdL1ZeroFlag(false); + } + pcPic->getSlice(pcSlice->getSliceIdx())->setMvdL1ZeroFlag(pcSlice->getMvdL1ZeroFlag()); + + pcPic->getPicSym()->initTiles(pcSlice->getPPS()); + pcPic->getPicSym()->initCtuTsRsAddrMaps(); + + Double lambda = 0.0; + Int actualHeadBits = 0; + Int actualTotalBits = 0; + Int estimatedBits = 0; + Int tmpBitsBeforeWriting = 0; + if ( m_pcCfg->getUseRateCtrl() ) + { + Int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( iGOPid ); + if ( pcPic->getSlice(0)->getSliceType() == I_SLICE ) + { + frameLevel = 0; + } + m_pcRateCtrl->initRCPic( frameLevel ); + estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits(); + + Int sliceQP = m_pcCfg->getInitialQP(); + if ( ( pcSlice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified + { + Int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 ); + Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)NumberBFrames ); + Double dQPFactor = 0.57*dLambda_scale; + Int SHIFT_QP = 12; + Int bitdepth_luma_qp_scale = 0; + Double qp_temp = (Double) sliceQP + bitdepth_luma_qp_scale - SHIFT_QP; + lambda = dQPFactor*pow( 2.0, qp_temp/3.0 ); + } + else if ( frameLevel == 0 ) // intra case, but use the model + { + m_pcSliceEncoder->calCostSliceI(pcPic); + + if ( m_pcCfg->getIntraPeriod() != 1 ) // do not refine allocated bits for all intra case + { + Int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits(); + bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits ); + if ( bits < 200 ) + { + bits = 200; + } + m_pcRateCtrl->getRCPic()->setTargetBits( bits ); + } + + list listPreviousPicture = m_pcRateCtrl->getPicList(); + m_pcRateCtrl->getRCPic()->getLCUInitTargetBits(); + lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType()); + sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture ); + } + else // normal case + { + list listPreviousPicture = m_pcRateCtrl->getPicList(); + lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType()); + sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture ); + } + + sliceQP = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, sliceQP ); + m_pcRateCtrl->getRCPic()->setPicEstQP( sliceQP ); + + m_pcSliceEncoder->resetQP( pcPic, sliceQP, lambda ); + } + + UInt uiNumSliceSegments = 1; + + + // Allocate some coders, now the number of tiles are known. + const Int numSubstreams = pcSlice->getPPS()->getNumSubstreams(); + std::vector substreamsOut(numSubstreams); + + // now compress (trial encode) the various slice segments (slices, and dependent slices) + { + const UInt numberOfCtusInFrame=pcPic->getPicSym()->getNumberOfCtusInFrame(); + pcSlice->setSliceCurStartCtuTsAddr( 0 ); + pcSlice->setSliceSegmentCurStartCtuTsAddr( 0 ); + + for(UInt nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; ) + { + m_pcSliceEncoder->precompressSlice( pcPic ); + m_pcSliceEncoder->compressSlice ( pcPic ); + + const UInt curSliceSegmentEnd = pcSlice->getSliceSegmentCurEndCtuTsAddr(); + if (curSliceSegmentEnd < numberOfCtusInFrame) + { + const Bool bNextSegmentIsDependentSlice=curSliceSegmentEndgetSliceCurEndCtuTsAddr(); + const UInt sliceBits=pcSlice->getSliceBits(); + pcPic->allocateNewSlice(); + // prepare for next slice + pcPic->setCurrSliceIdx ( uiNumSliceSegments ); + m_pcSliceEncoder->setSliceIdx ( uiNumSliceSegments ); + pcSlice = pcPic->getSlice ( uiNumSliceSegments ); + pcSlice->copySliceInfo ( pcPic->getSlice(uiNumSliceSegments-1) ); + pcSlice->setSliceIdx ( uiNumSliceSegments ); + if (bNextSegmentIsDependentSlice) + { + pcSlice->setSliceBits(sliceBits); + } + else + { + pcSlice->setSliceCurStartCtuTsAddr ( curSliceSegmentEnd ); + pcSlice->setSliceBits(0); + } + pcSlice->setDependentSliceSegmentFlag(bNextSegmentIsDependentSlice); + pcSlice->setSliceSegmentCurStartCtuTsAddr ( curSliceSegmentEnd ); + uiNumSliceSegments ++; + } + nextCtuTsAddr = curSliceSegmentEnd; + } + } + + pcSlice = pcPic->getSlice(0); + + // SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas + if( pcSlice->getSPS()->getUseSAO() && m_pcCfg->getSaoCtuBoundary() ) + { + m_pcSAO->getPreDBFStatistics(pcPic); + } + + //-- Loop filter + Bool bLFCrossTileBoundary = pcSlice->getPPS()->getLoopFilterAcrossTilesEnabledFlag(); + m_pcLoopFilter->setCfg(bLFCrossTileBoundary); + if ( m_pcCfg->getDeblockingFilterMetric() ) + { + dblMetric(pcPic, uiNumSliceSegments); + } + m_pcLoopFilter->loopFilterPic( pcPic ); + + /////////////////////////////////////////////////////////////////////////////////////////////////// File writing + // Set entropy coder + m_pcEntropyCoder->setEntropyCoder ( m_pcCavlcCoder, pcSlice ); + + /* write various header sets. */ + if ( m_bSeqFirst ) + { + OutputNALUnit nalu(NAL_UNIT_VPS); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_pcEntropyCoder->encodeVPS(m_pcEncTop->getVPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8; + + nalu = NALUnit(NAL_UNIT_SPS); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + if (m_bSeqFirst) + { + pcSlice->getSPS()->setNumLongTermRefPicSPS(m_numLongTermRefPicSPS); + assert (m_numLongTermRefPicSPS <= MAX_NUM_LONG_TERM_REF_PICS); + for (Int k = 0; k < m_numLongTermRefPicSPS; k++) + { + pcSlice->getSPS()->setLtRefPicPocLsbSps(k, m_ltRefPicPocLsbSps[k]); + pcSlice->getSPS()->setUsedByCurrPicLtSPSFlag(k, m_ltRefPicUsedByCurrPicFlag[k]); + } + } + if( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) + { + UInt maxCU = m_pcCfg->getSliceArgument() >> ( pcSlice->getSPS()->getMaxCUDepth() << 1); + UInt numDU = ( m_pcCfg->getSliceMode() == FIXED_NUMBER_OF_CTU ) ? ( pcPic->getNumberOfCtusInFrame() / maxCU ) : ( 0 ); + if( pcPic->getNumberOfCtusInFrame() % maxCU != 0 || numDU == 0 ) + { + numDU ++; + } + pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->setNumDU( numDU ); + pcSlice->getSPS()->setHrdParameters( m_pcCfg->getFrameRate(), numDU, m_pcCfg->getTargetBitrate(), ( m_pcCfg->getIntraPeriod() > 0 ) ); + } + if( m_pcCfg->getBufferingPeriodSEIEnabled() || m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) + { + pcSlice->getSPS()->getVuiParameters()->setHrdParametersPresentFlag( true ); + } + m_pcEntropyCoder->encodeSPS(pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8; + + nalu = NALUnit(NAL_UNIT_PPS); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_pcEntropyCoder->encodePPS(pcSlice->getPPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8; + + xCreateLeadingSEIMessages(accessUnit, pcSlice->getSPS()); + + m_bSeqFirst = false; + } + + if (writeSOP) // write SOP description SEI (if enabled) at the beginning of GOP + { + Int SOPcurrPOC = pocCurr; + + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + SEISOPDescription SOPDescriptionSEI; + SOPDescriptionSEI.m_sopSeqParameterSetId = pcSlice->getSPS()->getSPSId(); + + UInt i = 0; + UInt prevEntryId = iGOPid; + for (Int j = iGOPid; j < m_iGopSize; j++) + { + Int deltaPOC = m_pcCfg->getGOPEntry(j).m_POC - m_pcCfg->getGOPEntry(prevEntryId).m_POC; + if ((SOPcurrPOC + deltaPOC) < m_pcCfg->getFramesToBeEncoded()) + { + SOPcurrPOC += deltaPOC; + SOPDescriptionSEI.m_sopDescVclNaluType[i] = getNalUnitType(SOPcurrPOC, m_iLastIDR, isField); + SOPDescriptionSEI.m_sopDescTemporalId[i] = m_pcCfg->getGOPEntry(j).m_temporalId; + SOPDescriptionSEI.m_sopDescStRpsIdx[i] = m_pcEncTop->getReferencePictureSetIdxForSOP(pcSlice, SOPcurrPOC, j); + SOPDescriptionSEI.m_sopDescPocDelta[i] = deltaPOC; + + prevEntryId = j; + i++; + } + } + + SOPDescriptionSEI.m_numPicsInSopMinus1 = i - 1; + + m_seiWriter.writeSEImessage( nalu.m_Bitstream, SOPDescriptionSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + + writeSOP = false; + } + + if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) && + ( pcSlice->getSPS()->getVuiParametersPresentFlag() ) && + ( ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNalHrdParametersPresentFlag() ) + || ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) ) + { + if( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getSubPicCpbParamsPresentFlag() ) + { + UInt numDU = pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNumDU(); + pictureTimingSEI.m_numDecodingUnitsMinus1 = ( numDU - 1 ); + pictureTimingSEI.m_duCommonCpbRemovalDelayFlag = false; + + if( pictureTimingSEI.m_numNalusInDuMinus1 == NULL ) + { + pictureTimingSEI.m_numNalusInDuMinus1 = new UInt[ numDU ]; + } + if( pictureTimingSEI.m_duCpbRemovalDelayMinus1 == NULL ) + { + pictureTimingSEI.m_duCpbRemovalDelayMinus1 = new UInt[ numDU ]; + } + if( accumBitsDU == NULL ) + { + accumBitsDU = new UInt[ numDU ]; + } + if( accumNalsDU == NULL ) + { + accumNalsDU = new UInt[ numDU ]; + } + } + pictureTimingSEI.m_auCpbRemovalDelay = std::min(std::max(1, m_totalCoded - m_lastBPSEI), static_cast(pow(2, static_cast(pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getCpbRemovalDelayLengthMinus1()+1)))); // Syntax element signalled as minus, hence the . + pictureTimingSEI.m_picDpbOutputDelay = pcSlice->getSPS()->getNumReorderPics(pcSlice->getSPS()->getMaxTLayers()-1) + pcSlice->getPOC() - m_totalCoded; +#if EFFICIENT_FIELD_IRAP + if(IRAPGOPid > 0 && IRAPGOPid < m_iGopSize) + { + // if pictures have been swapped there is likely one more picture delay on their tid. Very rough approximation + pictureTimingSEI.m_picDpbOutputDelay ++; + } +#endif + Int factor = pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getTickDivisorMinus2() + 2; + pictureTimingSEI.m_picDpbOutputDuDelay = factor * pictureTimingSEI.m_picDpbOutputDelay; + if( m_pcCfg->getDecodingUnitInfoSEIEnabled() ) + { + picSptDpbOutputDuDelay = factor * pictureTimingSEI.m_picDpbOutputDelay; + } + } + + if( ( m_pcCfg->getBufferingPeriodSEIEnabled() ) && ( pcSlice->getSliceType() == I_SLICE ) && + ( pcSlice->getSPS()->getVuiParametersPresentFlag() ) && + ( ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNalHrdParametersPresentFlag() ) + || ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) ) + { + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + SEIBufferingPeriod sei_buffering_period; + + UInt uiInitialCpbRemovalDelay = (90000/2); // 0.5 sec + sei_buffering_period.m_initialCpbRemovalDelay [0][0] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialCpbRemovalDelayOffset[0][0] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialCpbRemovalDelay [0][1] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialCpbRemovalDelayOffset[0][1] = uiInitialCpbRemovalDelay; + + Double dTmp = (Double)pcSlice->getSPS()->getVuiParameters()->getTimingInfo()->getNumUnitsInTick() / (Double)pcSlice->getSPS()->getVuiParameters()->getTimingInfo()->getTimeScale(); + + UInt uiTmp = (UInt)( dTmp * 90000.0 ); + uiInitialCpbRemovalDelay -= uiTmp; + uiInitialCpbRemovalDelay -= uiTmp / ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getTickDivisorMinus2() + 2 ); + sei_buffering_period.m_initialAltCpbRemovalDelay [0][0] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialAltCpbRemovalDelayOffset[0][0] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialAltCpbRemovalDelay [0][1] = uiInitialCpbRemovalDelay; + sei_buffering_period.m_initialAltCpbRemovalDelayOffset[0][1] = uiInitialCpbRemovalDelay; + + sei_buffering_period.m_rapCpbParamsPresentFlag = 0; + //for the concatenation, it can be set to one during splicing. + sei_buffering_period.m_concatenationFlag = 0; + //since the temporal layer HRD is not ready, we assumed it is fixed + sei_buffering_period.m_auCpbRemovalDelayDelta = 1; + + sei_buffering_period.m_cpbDelayOffset = 0; + sei_buffering_period.m_dpbDelayOffset = 0; + + m_seiWriter.writeSEImessage( nalu.m_Bitstream, sei_buffering_period, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + + { + UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit); + UInt offsetPosition = m_activeParameterSetSEIPresentInAU; // Insert BP SEI after APS SEI + AccessUnit::iterator it = accessUnit.begin(); + for(Int j = 0; j < seiPositionInAu + offsetPosition; j++) + { + it++; + } + accessUnit.insert(it, new NALUnitEBSP(nalu)); + m_bufferingPeriodSEIPresentInAU = true; + } + + if (m_pcCfg->getScalableNestingSEIEnabled()) + { + OutputNALUnit naluTmp(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&naluTmp.m_Bitstream); + scalableNestingSEI.m_nestedSEIs.clear(); + scalableNestingSEI.m_nestedSEIs.push_back(&sei_buffering_period); + m_seiWriter.writeSEImessage( naluTmp.m_Bitstream, scalableNestingSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(naluTmp.m_Bitstream); + UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit); + UInt offsetPosition = m_activeParameterSetSEIPresentInAU + m_bufferingPeriodSEIPresentInAU + m_pictureTimingSEIPresentInAU; // Insert BP SEI after non-nested APS, BP and PT SEIs + AccessUnit::iterator it = accessUnit.begin(); + for(Int j = 0; j < seiPositionInAu + offsetPosition; j++) + { + it++; + } + accessUnit.insert(it, new NALUnitEBSP(naluTmp)); + m_nestedBufferingPeriodSEIPresentInAU = true; + } + + m_lastBPSEI = m_totalCoded; + m_cpbRemovalDelay = 0; + } + m_cpbRemovalDelay ++; + + if(pcSlice->getSPS()->getVuiParametersPresentFlag() && m_pcCfg->getChromaSamplingFilterHintEnabled() && ( pcSlice->getSliceType() == I_SLICE )) + { + SEIChromaSamplingFilterHint *seiChromaSamplingFilterHint = xCreateSEIChromaSamplingFilterHint(m_pcCfg->getChromaLocInfoPresentFlag(), m_pcCfg->getChromaSamplingHorFilterIdc(), m_pcCfg->getChromaSamplingVerFilterIdc()); + + OutputNALUnit naluTmp(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&naluTmp.m_Bitstream); + m_seiWriter.writeSEImessage(naluTmp.m_Bitstream, *seiChromaSamplingFilterHint, pcSlice->getSPS()); + writeRBSPTrailingBits(naluTmp.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(naluTmp)); + delete seiChromaSamplingFilterHint; + } + + if( ( m_pcEncTop->getRecoveryPointSEIEnabled() ) && ( pcSlice->getSliceType() == I_SLICE ) ) + { + if( m_pcEncTop->getGradualDecodingRefreshInfoEnabled() && !pcSlice->getRapPicFlag() ) + { + // Gradual decoding refresh SEI + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + SEIGradualDecodingRefreshInfo seiGradualDecodingRefreshInfo; + seiGradualDecodingRefreshInfo.m_gdrForegroundFlag = true; // Indicating all "foreground" + + m_seiWriter.writeSEImessage( nalu.m_Bitstream, seiGradualDecodingRefreshInfo, pcSlice->getSPS() ); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + } + // Recovery point SEI + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + SEIRecoveryPoint sei_recovery_point; + sei_recovery_point.m_recoveryPocCnt = 0; + sei_recovery_point.m_exactMatchingFlag = ( pcSlice->getPOC() == 0 ) ? (true) : (false); + sei_recovery_point.m_brokenLinkFlag = false; +#if ALLOW_RECOVERY_POINT_AS_RAP + if(m_pcCfg->getDecodingRefreshType() == 3) + { + m_iLastRecoveryPicPOC = pocCurr; + } +#endif + + m_seiWriter.writeSEImessage( nalu.m_Bitstream, sei_recovery_point, pcSlice->getSPS() ); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + } + + if( m_pcEncTop->getNoDisplaySEITLayer() ) + { + if( pcSlice->getTLayer() >= m_pcEncTop->getNoDisplaySEITLayer() ) + { + // No display SEI + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + SEINoDisplay seiNoDisplay; + seiNoDisplay.m_noDisplay = true; + + m_seiWriter.writeSEImessage( nalu.m_Bitstream, seiNoDisplay, pcSlice->getSPS() ); + writeRBSPTrailingBits(nalu.m_Bitstream); + accessUnit.push_back(new NALUnitEBSP(nalu)); + } + } + + /* use the main bitstream buffer for storing the marshalled picture */ + m_pcEntropyCoder->setBitstream(NULL); + + pcSlice = pcPic->getSlice(0); + + if (pcSlice->getSPS()->getUseSAO()) + { + Bool sliceEnabled[MAX_NUM_COMPONENT]; + TComBitCounter tempBitCounter; + tempBitCounter.resetBits(); + m_pcEncTop->getRDGoOnSbacCoder()->setBitstream(&tempBitCounter); + m_pcSAO->initRDOCabacCoder(m_pcEncTop->getRDGoOnSbacCoder(), pcSlice); + m_pcSAO->SAOProcess(pcPic, sliceEnabled, pcPic->getSlice(0)->getLambdas() +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , m_pcCfg->getSaoCtuBoundary() +#endif + ); + m_pcSAO->PCMLFDisableProcess(pcPic); + m_pcEncTop->getRDGoOnSbacCoder()->setBitstream(NULL); + + //assign SAO slice header + for(Int s=0; s< uiNumSliceSegments; s++) + { + pcPic->getSlice(s)->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, sliceEnabled[COMPONENT_Y]); + assert(sliceEnabled[COMPONENT_Cb] == sliceEnabled[COMPONENT_Cr]); + pcPic->getSlice(s)->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]); + } + } + + // pcSlice is currently slice 0. + Int64 binCountsInNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10) + Int64 numBytesInVclNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10) + + for( UInt sliceSegmentStartCtuTsAddr = 0, sliceIdxCount=0; sliceSegmentStartCtuTsAddr < pcPic->getPicSym()->getNumberOfCtusInFrame(); sliceIdxCount++, sliceSegmentStartCtuTsAddr=pcSlice->getSliceSegmentCurEndCtuTsAddr() ) + { + pcSlice = pcPic->getSlice(sliceIdxCount); + if(sliceIdxCount > 0 && pcSlice->getSliceType()!= I_SLICE) + { + pcSlice->checkColRefIdx(sliceIdxCount, pcPic); + } + pcPic->setCurrSliceIdx(sliceIdxCount); + m_pcSliceEncoder->setSliceIdx(sliceIdxCount); + + pcSlice->setRPS(pcPic->getSlice(0)->getRPS()); + pcSlice->setRPSidx(pcPic->getSlice(0)->getRPSidx()); + + for ( UInt ui = 0 ; ui < numSubstreams; ui++ ) + { + substreamsOut[ui].clear(); + } + + m_pcEntropyCoder->setEntropyCoder ( m_pcCavlcCoder, pcSlice ); + m_pcEntropyCoder->resetEntropy (); + /* start slice NALunit */ + OutputNALUnit nalu( pcSlice->getNalUnitType(), pcSlice->getTLayer() ); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + + pcSlice->setNoRaslOutputFlag(false); + if (pcSlice->isIRAP()) + { + if (pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_BLA_W_LP && pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_IDR_N_LP) + { + pcSlice->setNoRaslOutputFlag(true); + } + //the inference for NoOutputPriorPicsFlag + // KJS: This cannot happen at the encoder + if (!m_bFirst && pcSlice->isIRAP() && pcSlice->getNoRaslOutputFlag()) + { + if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA) + { + pcSlice->setNoOutputPriorPicsFlag(true); + } + } + } + + tmpBitsBeforeWriting = m_pcEntropyCoder->getNumberOfWrittenBits(); + m_pcEntropyCoder->encodeSliceHeader(pcSlice); + actualHeadBits += ( m_pcEntropyCoder->getNumberOfWrittenBits() - tmpBitsBeforeWriting ); + + pcSlice->setFinalized(true); + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + g_bFinalEncode = true; +#endif + + pcSlice->clearSubstreamSizes( ); + { + UInt numBinsCoded = 0; + m_pcSliceEncoder->encodeSlice(pcPic, &(substreamsOut[0]), numBinsCoded); + binCountsInNalUnits+=numBinsCoded; + } + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + g_bFinalEncode = false; +#endif + + { + // Construct the final bitstream by concatenating substreams. + // The final bitstream is either nalu.m_Bitstream or pcBitstreamRedirect; + // Complete the slice header info. + m_pcEntropyCoder->setEntropyCoder ( m_pcCavlcCoder, pcSlice ); + m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); + m_pcEntropyCoder->encodeTilesWPPEntryPoint( pcSlice ); + + // Append substreams... + TComOutputBitstream *pcOut = pcBitstreamRedirect; + const Int numZeroSubstreamsAtStartOfSlice = pcPic->getSubstreamForCtuAddr(pcSlice->getSliceSegmentCurStartCtuTsAddr(), false, pcSlice); + const Int numSubstreamsToCode = pcSlice->getNumberOfSubstreamSizes()+1; + for ( UInt ui = 0 ; ui < numSubstreamsToCode; ui++ ) + { + pcOut->addSubstream(&(substreamsOut[ui+numZeroSubstreamsAtStartOfSlice])); + } + } + + // If current NALU is the first NALU of slice (containing slice header) and more NALUs exist (due to multiple dependent slices) then buffer it. + // If current NALU is the last NALU of slice and a NALU was buffered, then (a) Write current NALU (b) Update an write buffered NALU at approproate location in NALU list. + Bool bNALUAlignedWrittenToList = false; // used to ensure current NALU is not written more than once to the NALU list. + xAttachSliceDataToNalUnit(nalu, pcBitstreamRedirect); + accessUnit.push_back(new NALUnitEBSP(nalu)); + actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8; + numBytesInVclNalUnits += Int64(accessUnit.back()->m_nalUnitData.str().size()); + bNALUAlignedWrittenToList = true; + + if (!bNALUAlignedWrittenToList) + { + nalu.m_Bitstream.writeAlignZero(); + accessUnit.push_back(new NALUnitEBSP(nalu)); + } + + if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) && + ( pcSlice->getSPS()->getVuiParametersPresentFlag() ) && + ( ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNalHrdParametersPresentFlag() ) + || ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) && + ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getSubPicCpbParamsPresentFlag() ) ) + { + UInt numNalus = 0; + UInt numRBSPBytes = 0; + for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++) + { + UInt numRBSPBytes_nal = UInt((*it)->m_nalUnitData.str().size()); + if ((*it)->m_nalUnitType != NAL_UNIT_PREFIX_SEI && (*it)->m_nalUnitType != NAL_UNIT_SUFFIX_SEI) + { + numRBSPBytes += numRBSPBytes_nal; + numNalus ++; + } + } + accumBitsDU[ pcSlice->getSliceIdx() ] = ( numRBSPBytes << 3 ); + accumNalsDU[ pcSlice->getSliceIdx() ] = numNalus; // SEI not counted for bit count; hence shouldn't be counted for # of NALUs - only for consistency + } + } // end iteration over slices + + // cabac_zero_words processing + { + const Int log2subWidthCxsubHeightC = (pcPic->getComponentScaleX(COMPONENT_Cb)+pcPic->getComponentScaleY(COMPONENT_Cb)); + const Int minCuWidth = pcPic->getMinCUWidth(); + const Int minCuHeight = pcPic->getMinCUHeight(); + const Int paddedWidth = ((pcSlice->getSPS()->getPicWidthInLumaSamples() + minCuWidth - 1) / minCuWidth) * minCuWidth; + const Int paddedHeight= ((pcSlice->getSPS()->getPicHeightInLumaSamples() + minCuHeight - 1) / minCuHeight) * minCuHeight; + const Int rawBits = paddedWidth * paddedHeight * + (g_bitDepth[CHANNEL_TYPE_LUMA] + 2*(g_bitDepth[CHANNEL_TYPE_CHROMA]>>log2subWidthCxsubHeightC)); + const Int64 threshold = (32LL/3)*numBytesInVclNalUnits + (rawBits/32); + if (binCountsInNalUnits >= threshold) + { + // need to add additional cabac zero words (each one accounts for 3 bytes (=00 00 03)) to increase numBytesInVclNalUnits + const Int64 targetNumBytesInVclNalUnits = ((binCountsInNalUnits - (rawBits/32))*3+31)/32; + const Int64 numberOfAdditionalBytesNeeded=targetNumBytesInVclNalUnits - numBytesInVclNalUnits; + + if (numberOfAdditionalBytesNeeded>0) // It should be! + { + const Int64 numberOfAdditionalCabacZeroWords=(numberOfAdditionalBytesNeeded+2)/3; + const Int64 numberOfAdditionalCabacZeroBytes=numberOfAdditionalCabacZeroWords*3; + if (m_pcCfg->getCabacZeroWordPaddingEnabled()) + { + std::vector zeroBytesPadding(numberOfAdditionalCabacZeroBytes, Char(0)); + for(Int64 i=0; im_nalUnitData.write(&(zeroBytesPadding[0]), numberOfAdditionalCabacZeroBytes); + printf("Adding %lld bytes of padding\n", numberOfAdditionalCabacZeroWords*3); + } + else + { + printf("Standard would normally require adding %lld bytes of padding\n", numberOfAdditionalCabacZeroWords*3); + } + } + } + } + + pcPic->compressMotion(); + + //-- For time output for each slice + Double dEncTime = (Double)(clock()-iBeforeTime) / CLOCKS_PER_SEC; + + std::string digestStr; + if (m_pcCfg->getDecodedPictureHashSEIEnabled()) + { + /* calculate MD5sum for entire reconstructed picture */ + SEIDecodedPictureHash sei_recon_picture_digest; + if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 1) + { + sei_recon_picture_digest.method = SEIDecodedPictureHash::MD5; + UInt numChar=calcMD5(*pcPic->getPicYuvRec(), sei_recon_picture_digest.m_digest); + digestStr = digestToString(sei_recon_picture_digest.m_digest, numChar); + } + else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 2) + { + sei_recon_picture_digest.method = SEIDecodedPictureHash::CRC; + UInt numChar=calcCRC(*pcPic->getPicYuvRec(), sei_recon_picture_digest.m_digest); + digestStr = digestToString(sei_recon_picture_digest.m_digest, numChar); + } + else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 3) + { + sei_recon_picture_digest.method = SEIDecodedPictureHash::CHECKSUM; + UInt numChar=calcChecksum(*pcPic->getPicYuvRec(), sei_recon_picture_digest.m_digest); + digestStr = digestToString(sei_recon_picture_digest.m_digest, numChar); + } + OutputNALUnit nalu(NAL_UNIT_SUFFIX_SEI, pcSlice->getTLayer()); + + /* write the SEI messages */ + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, sei_recon_picture_digest, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + + accessUnit.insert(accessUnit.end(), new NALUnitEBSP(nalu)); + } + if (m_pcCfg->getTemporalLevel0IndexSEIEnabled()) + { + SEITemporalLevel0Index sei_temporal_level0_index; + if (pcSlice->getRapPicFlag()) + { + m_tl0Idx = 0; + m_rapIdx = (m_rapIdx + 1) & 0xFF; + } + else + { + m_tl0Idx = (m_tl0Idx + (pcSlice->getTLayer() ? 0 : 1)) & 0xFF; + } + sei_temporal_level0_index.tl0Idx = m_tl0Idx; + sei_temporal_level0_index.rapIdx = m_rapIdx; + + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); + + /* write the SEI messages */ + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, sei_temporal_level0_index, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + + /* insert the SEI message NALUnit before any Slice NALUnits */ + AccessUnit::iterator it = find_if(accessUnit.begin(), accessUnit.end(), mem_fun(&NALUnit::isSlice)); + accessUnit.insert(it, new NALUnitEBSP(nalu)); + } + + m_pcCfg->setEncodedFlag(iGOPid, true); + xCalculateAddPSNR( pcPic, pcPic->getPicYuvRec(), accessUnit, dEncTime, snr_conversion, printFrameMSE ); + + //In case of field coding, compute the interlaced PSNR for both fields + if(isField) + { + Bool bothFieldsAreEncoded = false; + Int correspondingFieldPOC = pcPic->getPOC(); + Int currentPicGOPPoc = m_pcCfg->getGOPEntry(iGOPid).m_POC; + if(pcPic->getPOC() == 0) + { + // particular case for POC 0 and 1. + // If they are not encoded first and separately from other pictures, we need to change this + // POC 0 is always encoded first then POC 1 is encoded + bothFieldsAreEncoded = false; + } + else if(pcPic->getPOC() == 1) + { + // if we are at POC 1, POC 0 has been encoded for sure + correspondingFieldPOC = 0; + bothFieldsAreEncoded = true; + } + else + { + if(pcPic->getPOC()%2 == 1) + { + correspondingFieldPOC -= 1; // all odd POC are associated with the preceding even POC (e.g poc 1 is associated to poc 0) + currentPicGOPPoc -= 1; + } + else + { + correspondingFieldPOC += 1; // all even POC are associated with the following odd POC (e.g poc 0 is associated to poc 1) + currentPicGOPPoc += 1; + } + for(Int i = 0; i < m_iGopSize; i ++) + { + if(m_pcCfg->getGOPEntry(i).m_POC == currentPicGOPPoc) + { + bothFieldsAreEncoded = m_pcCfg->getGOPEntry(i).m_isEncoded; + break; + } + } + } + + if(bothFieldsAreEncoded) + { + //get complementary top field + TComList::iterator iterPic = rcListPic.begin(); + while ((*iterPic)->getPOC() != correspondingFieldPOC) + { + iterPic ++; + } + TComPic* correspondingFieldPic = *(iterPic); + + if( (pcPic->isTopField() && isTff) || (!pcPic->isTopField() && !isTff)) + { + xCalculateInterlacedAddPSNR(pcPic, correspondingFieldPic, pcPic->getPicYuvRec(), correspondingFieldPic->getPicYuvRec(), accessUnit, dEncTime, snr_conversion, printFrameMSE ); + } + else + { + xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getPicYuvRec(), pcPic->getPicYuvRec(), accessUnit, dEncTime, snr_conversion, printFrameMSE ); + } + } + } + +#if VERBOSE_FRAME + if (!digestStr.empty()) + { + if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 1) + { + printf(" [MD5:%s]", digestStr.c_str()); + } + else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 2) + { + printf(" [CRC:%s]", digestStr.c_str()); + } + else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 3) + { + printf(" [Checksum:%s]", digestStr.c_str()); + } + } +#endif + + if ( m_pcCfg->getUseRateCtrl() ) + { + Double avgQP = m_pcRateCtrl->getRCPic()->calAverageQP(); + Double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda(); + if ( avgLambda < 0.0 ) + { + avgLambda = lambda; + } + + m_pcRateCtrl->getRCPic()->updateAfterPicture( actualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->getSliceType()); + m_pcRateCtrl->getRCPic()->addToPictureLsit( m_pcRateCtrl->getPicList() ); + + m_pcRateCtrl->getRCSeq()->updateAfterPic( actualTotalBits ); + if ( pcSlice->getSliceType() != I_SLICE ) + { + m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualTotalBits ); + } + else // for intra picture, the estimated bits are used to update the current status in the GOP + { + m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits ); + } + } + + if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) && + ( pcSlice->getSPS()->getVuiParametersPresentFlag() ) && + ( ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNalHrdParametersPresentFlag() ) + || ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) ) + { + TComVUI *vui = pcSlice->getSPS()->getVuiParameters(); + TComHRD *hrd = vui->getHrdParameters(); + + if( hrd->getSubPicCpbParamsPresentFlag() ) + { + Int i; + UInt64 ui64Tmp; + UInt uiPrev = 0; + UInt numDU = ( pictureTimingSEI.m_numDecodingUnitsMinus1 + 1 ); + UInt *pCRD = &pictureTimingSEI.m_duCpbRemovalDelayMinus1[0]; + UInt maxDiff = ( hrd->getTickDivisorMinus2() + 2 ) - 1; + + for( i = 0; i < numDU; i ++ ) + { + pictureTimingSEI.m_numNalusInDuMinus1[ i ] = ( i == 0 ) ? ( accumNalsDU[ i ] - 1 ) : ( accumNalsDU[ i ] - accumNalsDU[ i - 1] - 1 ); + } + + if( numDU == 1 ) + { + pCRD[ 0 ] = 0; /* don't care */ + } + else + { + pCRD[ numDU - 1 ] = 0;/* by definition */ + UInt tmp = 0; + UInt accum = 0; + + for( i = ( numDU - 2 ); i >= 0; i -- ) + { + ui64Tmp = ( ( ( accumBitsDU[ numDU - 1 ] - accumBitsDU[ i ] ) * ( vui->getTimingInfo()->getTimeScale() / vui->getTimingInfo()->getNumUnitsInTick() ) * ( hrd->getTickDivisorMinus2() + 2 ) ) / ( m_pcCfg->getTargetBitrate() ) ); + if( (UInt)ui64Tmp > maxDiff ) + { + tmp ++; + } + } + uiPrev = 0; + + UInt flag = 0; + for( i = ( numDU - 2 ); i >= 0; i -- ) + { + flag = 0; + ui64Tmp = ( ( ( accumBitsDU[ numDU - 1 ] - accumBitsDU[ i ] ) * ( vui->getTimingInfo()->getTimeScale() / vui->getTimingInfo()->getNumUnitsInTick() ) * ( hrd->getTickDivisorMinus2() + 2 ) ) / ( m_pcCfg->getTargetBitrate() ) ); + + if( (UInt)ui64Tmp > maxDiff ) + { + if(uiPrev >= maxDiff - tmp) + { + ui64Tmp = uiPrev + 1; + flag = 1; + } + else ui64Tmp = maxDiff - tmp + 1; + } + pCRD[ i ] = (UInt)ui64Tmp - uiPrev - 1; + if( (Int)pCRD[ i ] < 0 ) + { + pCRD[ i ] = 0; + } + else if (tmp > 0 && flag == 1) + { + tmp --; + } + accum += pCRD[ i ] + 1; + uiPrev = accum; + } + } + } + + if( m_pcCfg->getPictureTimingSEIEnabled() ) + { + { + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI, pcSlice->getTLayer()); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + pictureTimingSEI.m_picStruct = (isField && pcSlice->getPic()->isTopField())? 1 : isField? 2 : 0; + m_seiWriter.writeSEImessage(nalu.m_Bitstream, pictureTimingSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit); + UInt offsetPosition = m_activeParameterSetSEIPresentInAU + + m_bufferingPeriodSEIPresentInAU; // Insert PT SEI after APS and BP SEI + AccessUnit::iterator it = accessUnit.begin(); + for(Int j = 0; j < seiPositionInAu + offsetPosition; j++) + { + it++; + } + accessUnit.insert(it, new NALUnitEBSP(nalu)); + m_pictureTimingSEIPresentInAU = true; + } + + if ( m_pcCfg->getScalableNestingSEIEnabled() ) // put picture timing SEI into scalable nesting SEI + { + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI, pcSlice->getTLayer()); + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + scalableNestingSEI.m_nestedSEIs.clear(); + scalableNestingSEI.m_nestedSEIs.push_back(&pictureTimingSEI); + m_seiWriter.writeSEImessage(nalu.m_Bitstream, scalableNestingSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit); + UInt offsetPosition = m_activeParameterSetSEIPresentInAU + + m_bufferingPeriodSEIPresentInAU + m_pictureTimingSEIPresentInAU + m_nestedBufferingPeriodSEIPresentInAU; // Insert PT SEI after APS and BP SEI + AccessUnit::iterator it = accessUnit.begin(); + for(Int j = 0; j < seiPositionInAu + offsetPosition; j++) + { + it++; + } + accessUnit.insert(it, new NALUnitEBSP(nalu)); + m_nestedPictureTimingSEIPresentInAU = true; + } + } + + if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && hrd->getSubPicCpbParamsPresentFlag() ) + { + m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); + for( Int i = 0; i < ( pictureTimingSEI.m_numDecodingUnitsMinus1 + 1 ); i ++ ) + { + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI, pcSlice->getTLayer()); + + SEIDecodingUnitInfo tempSEI; + tempSEI.m_decodingUnitIdx = i; + tempSEI.m_duSptCpbRemovalDelay = pictureTimingSEI.m_duCpbRemovalDelayMinus1[i] + 1; + tempSEI.m_dpbOutputDuDelayPresentFlag = false; + tempSEI.m_picSptDpbOutputDuDelay = picSptDpbOutputDuDelay; + + // Insert the first one in the right location, before the first slice + if(i == 0) + { + // Insert before the first slice. + m_seiWriter.writeSEImessage(nalu.m_Bitstream, tempSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + + UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit); + UInt offsetPosition = m_activeParameterSetSEIPresentInAU + + m_bufferingPeriodSEIPresentInAU + + m_pictureTimingSEIPresentInAU; // Insert DU info SEI after APS, BP and PT SEI + AccessUnit::iterator it = accessUnit.begin(); + for(Int j = 0; j < seiPositionInAu + offsetPosition; j++) + { + it++; + } + accessUnit.insert(it, new NALUnitEBSP(nalu)); + } + else + { + // For the second decoding unit onwards we know how many NALUs are present + AccessUnit::iterator it = accessUnit.begin(); + for (Int ctr = 0; it != accessUnit.end(); it++) + { + if(ctr == accumNalsDU[ i - 1 ]) + { + // Insert before the first slice. + m_seiWriter.writeSEImessage(nalu.m_Bitstream, tempSEI, pcSlice->getSPS()); + writeRBSPTrailingBits(nalu.m_Bitstream); + + accessUnit.insert(it, new NALUnitEBSP(nalu)); + break; + } + if ((*it)->m_nalUnitType != NAL_UNIT_PREFIX_SEI && (*it)->m_nalUnitType != NAL_UNIT_SUFFIX_SEI) + { + ctr++; + } + } + } + } + } + } + + xResetNonNestedSEIPresentFlags(); + xResetNestedSEIPresentFlags(); + + pcPic->getPicYuvRec()->copyToPic(pcPicYuvRecOut); + + pcPic->setReconMark ( true ); + m_bFirst = false; + m_iNumPicCoded++; + m_totalCoded ++; + /* logging: insert a newline at end of picture period */ +#if VERBOSE_FRAME + printf("\n"); + fflush(stdout); +#endif + +#if EFFICIENT_FIELD_IRAP + if(IRAPtoReorder) + { + if(swapIRAPForward) + { + if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid +1; + IRAPtoReorder = false; + } + else if(iGOPid == IRAPGOPid +1) + { + iGOPid --; + } + } + else + { + if(iGOPid == IRAPGOPid) + { + iGOPid = IRAPGOPid -1; + } + else if(iGOPid == IRAPGOPid -1) + { + iGOPid = IRAPGOPid; + IRAPtoReorder = false; + } + } + } +#endif + } // iGOPid-loop + + delete pcBitstreamRedirect; + + if( accumBitsDU != NULL) delete accumBitsDU; + if( accumNalsDU != NULL) delete accumNalsDU; + + assert ( (m_iNumPicCoded == iNumPicRcvd) ); +} + +Void TEncGOP::printOutSummary(UInt uiNumAllPicCoded, Bool isField, const Bool printMSEBasedSNR, const Bool printSequenceMSE) +{ + assert (uiNumAllPicCoded == m_gcAnalyzeAll.getNumPic()); + + + //--CFG_KDY + const Int rateMultiplier=(isField?2:1); + m_gcAnalyzeAll.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier ); + m_gcAnalyzeI.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier ); + m_gcAnalyzeP.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier ); + m_gcAnalyzeB.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier ); + const ChromaFormat chFmt = m_pcCfg->getChromaFormatIdc(); + + //-- all + printf( "\n\nSUMMARY --------------------------------------------------------\n" ); + m_gcAnalyzeAll.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE); + + printf( "\n\nI Slices--------------------------------------------------------\n" ); + m_gcAnalyzeI.printOut('i', chFmt, printMSEBasedSNR, printSequenceMSE); + + printf( "\n\nP Slices--------------------------------------------------------\n" ); + m_gcAnalyzeP.printOut('p', chFmt, printMSEBasedSNR, printSequenceMSE); + + printf( "\n\nB Slices--------------------------------------------------------\n" ); + m_gcAnalyzeB.printOut('b', chFmt, printMSEBasedSNR, printSequenceMSE); + +#if _SUMMARY_OUT_ + m_gcAnalyzeAll.printSummary(chFmt, printSequenceMSE); +#endif +#if _SUMMARY_PIC_ + m_gcAnalyzeI.printSummary(chFmt, printSequenceMSE,'I'); + m_gcAnalyzeP.printSummary(chFmt, printSequenceMSE,'P'); + m_gcAnalyzeB.printSummary(chFmt, printSequenceMSE,'B'); +#endif + + if(isField) + { + //-- interlaced summary + m_gcAnalyzeAll_in.setFrmRate( m_pcCfg->getFrameRate()); + m_gcAnalyzeAll_in.setBits(m_gcAnalyzeAll.getBits()); + // prior to the above statement, the interlace analyser does not contain the correct total number of bits. + + printf( "\n\nSUMMARY INTERLACED ---------------------------------------------\n" ); + m_gcAnalyzeAll_in.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE); + +#if _SUMMARY_OUT_ + m_gcAnalyzeAll_in.printSummary(chFmt, printSequenceMSE); +#endif + } + + printf("\nRVM: %.3lf\n" , xCalculateRVM()); +} + +Void TEncGOP::preLoopFilterPicAll( TComPic* pcPic, UInt64& ruiDist ) +{ + Bool bCalcDist = false; + m_pcLoopFilter->setCfg(m_pcCfg->getLFCrossTileBoundaryFlag()); + m_pcLoopFilter->loopFilterPic( pcPic ); + + if (!bCalcDist) + ruiDist = xFindDistortionFrame(pcPic->getPicYuvOrg(), pcPic->getPicYuvRec()); +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + + +Void TEncGOP::xInitGOP( Int iPOCLast, Int iNumPicRcvd, TComList& rcListPic, TComList& rcListPicYuvRecOut, Bool isField ) +{ + assert( iNumPicRcvd > 0 ); + // Exception for the first frames + if ( ( isField && (iPOCLast == 0 || iPOCLast == 1) ) || (!isField && (iPOCLast == 0)) ) + { + m_iGopSize = 1; + } + else + { + m_iGopSize = m_pcCfg->getGOPSize(); + } + assert (m_iGopSize > 0); + + return; +} + + +Void TEncGOP::xGetBuffer( TComList& rcListPic, + TComList& rcListPicYuvRecOut, + Int iNumPicRcvd, + Int iTimeOffset, + TComPic*& rpcPic, + TComPicYuv*& rpcPicYuvRecOut, + Int pocCurr, + Bool isField) +{ + Int i; + // Rec. output + TComList::iterator iterPicYuvRec = rcListPicYuvRecOut.end(); + + if (isField && pocCurr > 1 && m_iGopSize!=1) + { + iTimeOffset--; + } + + for ( i = 0; i < (iNumPicRcvd - iTimeOffset + 1); i++ ) + { + iterPicYuvRec--; + } + + rpcPicYuvRecOut = *(iterPicYuvRec); + + // Current pic. + TComList::iterator iterPic = rcListPic.begin(); + while (iterPic != rcListPic.end()) + { + rpcPic = *(iterPic); + rpcPic->setCurrSliceIdx(0); + if (rpcPic->getPOC() == pocCurr) + { + break; + } + iterPic++; + } + + assert (rpcPic != NULL); + assert (rpcPic->getPOC() == pocCurr); + + return; +} + +UInt64 TEncGOP::xFindDistortionFrame (TComPicYuv* pcPic0, TComPicYuv* pcPic1) +{ + UInt64 uiTotalDiff = 0; + + for(Int chan=0; changetNumberValidComponents(); chan++) + { + const ComponentID ch=ComponentID(chan); + Pel* pSrc0 = pcPic0 ->getAddr(ch); + Pel* pSrc1 = pcPic1 ->getAddr(ch); + UInt uiShift = 2 * DISTORTION_PRECISION_ADJUSTMENT(g_bitDepth[toChannelType(ch)]-8); + + const Int iStride = pcPic0->getStride(ch); + const Int iWidth = pcPic0->getWidth(ch); + const Int iHeight = pcPic0->getHeight(ch); + + for(Int y = 0; y < iHeight; y++ ) + { + for(Int x = 0; x < iWidth; x++ ) + { + Intermediate_Int iTemp = pSrc0[x] - pSrc1[x]; + uiTotalDiff += UInt64((iTemp*iTemp) >> uiShift); + } + pSrc0 += iStride; + pSrc1 += iStride; + } + } + + return uiTotalDiff; +} + +#if VERBOSE_RATE +static const Char* nalUnitTypeToString(NalUnitType type) +{ + switch (type) + { + case NAL_UNIT_CODED_SLICE_TRAIL_R: return "TRAIL_R"; + case NAL_UNIT_CODED_SLICE_TRAIL_N: return "TRAIL_N"; + case NAL_UNIT_CODED_SLICE_TSA_R: return "TSA_R"; + case NAL_UNIT_CODED_SLICE_TSA_N: return "TSA_N"; + case NAL_UNIT_CODED_SLICE_STSA_R: return "STSA_R"; + case NAL_UNIT_CODED_SLICE_STSA_N: return "STSA_N"; + case NAL_UNIT_CODED_SLICE_BLA_W_LP: return "BLA_W_LP"; + case NAL_UNIT_CODED_SLICE_BLA_W_RADL: return "BLA_W_RADL"; + case NAL_UNIT_CODED_SLICE_BLA_N_LP: return "BLA_N_LP"; + case NAL_UNIT_CODED_SLICE_IDR_W_RADL: return "IDR_W_RADL"; + case NAL_UNIT_CODED_SLICE_IDR_N_LP: return "IDR_N_LP"; + case NAL_UNIT_CODED_SLICE_CRA: return "CRA"; + case NAL_UNIT_CODED_SLICE_RADL_R: return "RADL_R"; + case NAL_UNIT_CODED_SLICE_RADL_N: return "RADL_N"; + case NAL_UNIT_CODED_SLICE_RASL_R: return "RASL_R"; + case NAL_UNIT_CODED_SLICE_RASL_N: return "RASL_N"; + case NAL_UNIT_VPS: return "VPS"; + case NAL_UNIT_SPS: return "SPS"; + case NAL_UNIT_PPS: return "PPS"; + case NAL_UNIT_ACCESS_UNIT_DELIMITER: return "AUD"; + case NAL_UNIT_EOS: return "EOS"; + case NAL_UNIT_EOB: return "EOB"; + case NAL_UNIT_FILLER_DATA: return "FILLER"; + case NAL_UNIT_PREFIX_SEI: return "SEI"; + case NAL_UNIT_SUFFIX_SEI: return "SEI"; + default: return "UNK"; + } +} +#endif + +Void TEncGOP::xCalculateAddPSNR( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit& accessUnit, Double dEncTime, const InputColourSpaceConversion conversion, const Bool printFrameMSE ) +{ + Double dPSNR[MAX_NUM_COMPONENT]; + + for(Int i=0; igetWidth(COMPONENT_Y), pcPicD->getHeight(COMPONENT_Y), pcPicD->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); + TVideoIOYuv::ColourSpaceConvert(*pcPicD, cscd, conversion, g_bitDepth, false); + } + TComPicYuv &picd=(conversion==IPCOLOURSPACE_UNCHANGED)?*pcPicD : cscd; + + //===== calculate PSNR ===== + Double MSEyuvframe[MAX_NUM_COMPONENT] = {0, 0, 0}; + + for(Int chan=0; changetNumberValidComponents(); chan++) + { + const ComponentID ch=ComponentID(chan); + const Pel* pOrg = (conversion!=IPCOLOURSPACE_UNCHANGED) ? pcPic ->getPicYuvTrueOrg()->getAddr(ch) : pcPic ->getPicYuvOrg()->getAddr(ch); + Pel* pRec = picd.getAddr(ch); + const Int iStride = pcPicD->getStride(ch); + + const Int iWidth = pcPicD->getWidth (ch) - (m_pcEncTop->getPad(0) >> pcPic->getComponentScaleX(ch)); + const Int iHeight = pcPicD->getHeight(ch) - ((m_pcEncTop->getPad(1) >> (pcPic->isField()?1:0)) >> pcPic->getComponentScaleY(ch)); + + Int iSize = iWidth*iHeight; + + UInt64 uiSSDtemp=0; + for(Int y = 0; y < iHeight; y++ ) + { + for(Int x = 0; x < iWidth; x++ ) + { + Intermediate_Int iDiff = (Intermediate_Int)( pOrg[x] - pRec[x] ); + uiSSDtemp += iDiff * iDiff; + } + pOrg += iStride; + pRec += iStride; + } + const Int maxval = 255 << (g_bitDepth[toChannelType(ch)] - 8); + const Double fRefValue = (Double) maxval * maxval * iSize; + dPSNR[ch] = ( uiSSDtemp ? 10.0 * log10( fRefValue / (Double)uiSSDtemp ) : 999.99 ); + MSEyuvframe[ch] = (Double)uiSSDtemp/(iSize); + } + + + /* calculate the size of the access unit, excluding: + * - any AnnexB contributions (start_code_prefix, zero_byte, etc.,) + * - SEI NAL units + */ + UInt numRBSPBytes = 0; + for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++) + { + UInt numRBSPBytes_nal = UInt((*it)->m_nalUnitData.str().size()); +#if VERBOSE_RATE + printf("*** %6s numBytesInNALunit: %u\n", nalUnitTypeToString((*it)->m_nalUnitType), numRBSPBytes_nal); +#endif + if ((*it)->m_nalUnitType != NAL_UNIT_PREFIX_SEI && (*it)->m_nalUnitType != NAL_UNIT_SUFFIX_SEI) + { + numRBSPBytes += numRBSPBytes_nal; + } + } + + UInt uibits = numRBSPBytes * 8; + m_vRVM_RP.push_back( uibits ); + + //===== add PSNR ===== + m_gcAnalyzeAll.addResult (dPSNR, (Double)uibits, MSEyuvframe); + TComSlice* pcSlice = pcPic->getSlice(0); + if (pcSlice->isIntra()) + { + m_gcAnalyzeI.addResult (dPSNR, (Double)uibits, MSEyuvframe); + } + if (pcSlice->isInterP()) + { + m_gcAnalyzeP.addResult (dPSNR, (Double)uibits, MSEyuvframe); + } + if (pcSlice->isInterB()) + { + m_gcAnalyzeB.addResult (dPSNR, (Double)uibits, MSEyuvframe); + } + + Char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B'); + if (!pcSlice->isReferenced()) c += 32; + +#if VERBOSE_FRAME + +#if ADAPTIVE_QP_SELECTION + printf("POC %4d TId: %1d ( %c-SLICE, nQP %d QP %d ) %10d bits", + pcSlice->getPOC(), + pcSlice->getTLayer(), + c, + pcSlice->getSliceQpBase(), + pcSlice->getSliceQp(), + uibits ); +#else + printf("POC %4d TId: %1d ( %c-SLICE, QP %d ) %10d bits", + pcSlice->getPOC()-pcSlice->getLastIDR(), + pcSlice->getTLayer(), + c, + pcSlice->getSliceQp(), + uibits ); +#endif + + printf(" [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] ); + if (printFrameMSE) + { + printf(" [Y MSE %6.4lf U MSE %6.4lf V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] ); + } + printf(" [ET %5.0f ]", dEncTime ); + + for (Int iRefList = 0; iRefList < 2; iRefList++) + { + printf(" [L%d ", iRefList); + for (Int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(RefPicList(iRefList)); iRefIndex++) + { + printf ("%d ", pcSlice->getRefPOC(RefPicList(iRefList), iRefIndex)-pcSlice->getLastIDR()); + } + printf("]"); + } +#endif /* VERBOSE_FRAME */ + + cscd.destroy(); +} + +Void TEncGOP::xCalculateInterlacedAddPSNR( TComPic* pcPicOrgFirstField, TComPic* pcPicOrgSecondField, + TComPicYuv* pcPicRecFirstField, TComPicYuv* pcPicRecSecondField, + const AccessUnit& accessUnit, Double dEncTime, const InputColourSpaceConversion conversion, const Bool printFrameMSE ) +{ + Double dPSNR[MAX_NUM_COMPONENT]; + TComPic *apcPicOrgFields[2]={pcPicOrgFirstField, pcPicOrgSecondField}; + TComPicYuv *apcPicRecFields[2]={pcPicRecFirstField, pcPicRecSecondField}; + + for(Int i=0; igetChromaFormat()==apcPicRecFields[1]->getChromaFormat()); + const UInt numValidComponents=apcPicRecFields[0]->getNumberValidComponents(); + + for(Int chan=0; changetWidth(ch)==apcPicRecFields[1]->getWidth(ch)); + assert(apcPicRecFields[0]->getHeight(ch)==apcPicRecFields[1]->getHeight(ch)); + + UInt64 uiSSDtemp=0; + const Int iWidth = apcPicRecFields[0]->getWidth (ch) - (m_pcEncTop->getPad(0) >> apcPicRecFields[0]->getComponentScaleX(ch)); + const Int iHeight = apcPicRecFields[0]->getHeight(ch) - ((m_pcEncTop->getPad(1) >> 1) >> apcPicRecFields[0]->getComponentScaleY(ch)); + + Int iSize = iWidth*iHeight; + + for(UInt fieldNum=0; fieldNum<2; fieldNum++) + { + TComPic *pcPic=apcPicOrgFields[fieldNum]; + TComPicYuv *pcPicD=apcPicRecFields[fieldNum]; + + const Pel* pOrg = (conversion!=IPCOLOURSPACE_UNCHANGED) ? pcPic ->getPicYuvTrueOrg()->getAddr(ch) : pcPic ->getPicYuvOrg()->getAddr(ch); + Pel* pRec = pcPicD->getAddr(ch); + const Int iStride = pcPicD->getStride(ch); + + + for(Int y = 0; y < iHeight; y++ ) + { + for(Int x = 0; x < iWidth; x++ ) + { + Intermediate_Int iDiff = (Intermediate_Int)( pOrg[x] - pRec[x] ); + uiSSDtemp += iDiff * iDiff; + } + pOrg += iStride; + pRec += iStride; + } + } + const Int maxval = 255 << (g_bitDepth[toChannelType(ch)] - 8); + const Double fRefValue = (Double) maxval * maxval * iSize*2; + dPSNR[ch] = ( uiSSDtemp ? 10.0 * log10( fRefValue / (Double)uiSSDtemp ) : 999.99 ); + MSEyuvframe[ch] = (Double)uiSSDtemp/(iSize*2); + } + + UInt uibits = 0; // the number of bits for the pair is not calculated here - instead the overall total is used elsewhere. + + //===== add PSNR ===== + m_gcAnalyzeAll_in.addResult (dPSNR, (Double)uibits, MSEyuvframe); + + printf("\n Interlaced frame %d: [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", pcPicOrgSecondField->getPOC()/2 , dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] ); + if (printFrameMSE) + { + printf(" [Y MSE %6.4lf U MSE %6.4lf V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] ); + } + + for(UInt fieldNum=0; fieldNum<2; fieldNum++) + { + cscd[fieldNum].destroy(); + } +} + +/** Function for deciding the nal_unit_type. + * \param pocCurr POC of the current picture + * \returns the nal unit type of the picture + * This function checks the configuration and returns the appropriate nal_unit_type for the picture. + */ +NalUnitType TEncGOP::getNalUnitType(Int pocCurr, Int lastIDR, Bool isField) +{ + if (pocCurr == 0) + { + return NAL_UNIT_CODED_SLICE_IDR_W_RADL; + } + +#if EFFICIENT_FIELD_IRAP + if(isField && pocCurr == 1) + { + // to avoid the picture becoming an IRAP + return NAL_UNIT_CODED_SLICE_TRAIL_R; + } +#endif + +#if ALLOW_RECOVERY_POINT_AS_RAP + if(m_pcCfg->getDecodingRefreshType() != 3 && (pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0) +#else + if ((pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0) +#endif + { + if (m_pcCfg->getDecodingRefreshType() == 1) + { + return NAL_UNIT_CODED_SLICE_CRA; + } + else if (m_pcCfg->getDecodingRefreshType() == 2) + { + return NAL_UNIT_CODED_SLICE_IDR_W_RADL; + } + } + if(m_pocCRA>0) + { + if(pocCurr0) + { + if (pocCurr < lastIDR) + { + return NAL_UNIT_CODED_SLICE_RADL_R; + } + } + return NAL_UNIT_CODED_SLICE_TRAIL_R; +} + +Double TEncGOP::xCalculateRVM() +{ + Double dRVM = 0; + + if( m_pcCfg->getGOPSize() == 1 && m_pcCfg->getIntraPeriod() != 1 && m_pcCfg->getFramesToBeEncoded() > RVM_VCEGAM10_M * 2 ) + { + // calculate RVM only for lowdelay configurations + std::vector vRL , vB; + size_t N = m_vRVM_RP.size(); + vRL.resize( N ); + vB.resize( N ); + + Int i; + Double dRavg = 0 , dBavg = 0; + vB[RVM_VCEGAM10_M] = 0; + for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ ) + { + vRL[i] = 0; + for( Int j = i - RVM_VCEGAM10_M ; j <= i + RVM_VCEGAM10_M - 1 ; j++ ) + vRL[i] += m_vRVM_RP[j]; + vRL[i] /= ( 2 * RVM_VCEGAM10_M ); + vB[i] = vB[i-1] + m_vRVM_RP[i] - vRL[i]; + dRavg += m_vRVM_RP[i]; + dBavg += vB[i]; + } + + dRavg /= ( N - 2 * RVM_VCEGAM10_M ); + dBavg /= ( N - 2 * RVM_VCEGAM10_M ); + + Double dSigamB = 0; + for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ ) + { + Double tmp = vB[i] - dBavg; + dSigamB += tmp * tmp; + } + dSigamB = sqrt( dSigamB / ( N - 2 * RVM_VCEGAM10_M ) ); + + Double f = sqrt( 12.0 * ( RVM_VCEGAM10_M - 1 ) / ( RVM_VCEGAM10_M + 1 ) ); + + dRVM = dSigamB / dRavg * f; + } + + return( dRVM ); +} + +/** Attaches the input bitstream to the stream in the output NAL unit + Updates rNalu to contain concatenated bitstream. rpcBitstreamRedirect is cleared at the end of this function call. + * \param codedSliceData contains the coded slice data (bitstream) to be concatenated to rNalu + * \param rNalu target NAL unit + */ +Void TEncGOP::xAttachSliceDataToNalUnit (OutputNALUnit& rNalu, TComOutputBitstream* codedSliceData) +{ + // Byte-align + rNalu.m_Bitstream.writeByteAlignment(); // Slice header byte-alignment + + // Perform bitstream concatenation + if (codedSliceData->getNumberOfWrittenBits() > 0) + { + rNalu.m_Bitstream.addSubstream(codedSliceData); + } + + m_pcEntropyCoder->setBitstream(&rNalu.m_Bitstream); + + codedSliceData->clear(); +} + +// Function will arrange the long-term pictures in the decreasing order of poc_lsb_lt, +// and among the pictures with the same lsb, it arranges them in increasing delta_poc_msb_cycle_lt value +Void TEncGOP::arrangeLongtermPicturesInRPS(TComSlice *pcSlice, TComList& rcListPic) +{ + TComReferencePictureSet *rps = pcSlice->getRPS(); + if(!rps->getNumberOfLongtermPictures()) + { + return; + } + + // Arrange long-term reference pictures in the correct order of LSB and MSB, + // and assign values for pocLSBLT and MSB present flag + Int longtermPicsPoc[MAX_NUM_REF_PICS], longtermPicsLSB[MAX_NUM_REF_PICS], indices[MAX_NUM_REF_PICS]; + Int longtermPicsMSB[MAX_NUM_REF_PICS]; + Bool mSBPresentFlag[MAX_NUM_REF_PICS]; + ::memset(longtermPicsPoc, 0, sizeof(longtermPicsPoc)); // Store POC values of LTRP + ::memset(longtermPicsLSB, 0, sizeof(longtermPicsLSB)); // Store POC LSB values of LTRP + ::memset(longtermPicsMSB, 0, sizeof(longtermPicsMSB)); // Store POC LSB values of LTRP + ::memset(indices , 0, sizeof(indices)); // Indices to aid in tracking sorted LTRPs + ::memset(mSBPresentFlag , 0, sizeof(mSBPresentFlag)); // Indicate if MSB needs to be present + + // Get the long-term reference pictures + Int offset = rps->getNumberOfNegativePictures() + rps->getNumberOfPositivePictures(); + Int i, ctr = 0; + Int maxPicOrderCntLSB = 1 << pcSlice->getSPS()->getBitsForPOC(); + for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++) + { + longtermPicsPoc[ctr] = rps->getPOC(i); // LTRP POC + longtermPicsLSB[ctr] = getLSB(longtermPicsPoc[ctr], maxPicOrderCntLSB); // LTRP POC LSB + indices[ctr] = i; + longtermPicsMSB[ctr] = longtermPicsPoc[ctr] - longtermPicsLSB[ctr]; + } + Int numLongPics = rps->getNumberOfLongtermPictures(); + assert(ctr == numLongPics); + + // Arrange pictures in decreasing order of MSB; + for(i = 0; i < numLongPics; i++) + { + for(Int j = 0; j < numLongPics - 1; j++) + { + if(longtermPicsMSB[j] < longtermPicsMSB[j+1]) + { + std::swap(longtermPicsPoc[j], longtermPicsPoc[j+1]); + std::swap(longtermPicsLSB[j], longtermPicsLSB[j+1]); + std::swap(longtermPicsMSB[j], longtermPicsMSB[j+1]); + std::swap(indices[j] , indices[j+1] ); + } + } + } + + for(i = 0; i < numLongPics; i++) + { + // Check if MSB present flag should be enabled. + // Check if the buffer contains any pictures that have the same LSB. + TComList::iterator iterPic = rcListPic.begin(); + TComPic* pcPic; + while ( iterPic != rcListPic.end() ) + { + pcPic = *iterPic; + if( (getLSB(pcPic->getPOC(), maxPicOrderCntLSB) == longtermPicsLSB[i]) && // Same LSB + (pcPic->getSlice(0)->isReferenced()) && // Reference picture + (pcPic->getPOC() != longtermPicsPoc[i]) ) // Not the LTRP itself + { + mSBPresentFlag[i] = true; + break; + } + iterPic++; + } + } + + // tempArray for usedByCurr flag + Bool tempArray[MAX_NUM_REF_PICS]; ::memset(tempArray, 0, sizeof(tempArray)); + for(i = 0; i < numLongPics; i++) + { + tempArray[i] = rps->getUsed(indices[i]); + } + // Now write the final values; + ctr = 0; + Int currMSB = 0, currLSB = 0; + // currPicPoc = currMSB + currLSB + currLSB = getLSB(pcSlice->getPOC(), maxPicOrderCntLSB); + currMSB = pcSlice->getPOC() - currLSB; + + for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++) + { + rps->setPOC (i, longtermPicsPoc[ctr]); + rps->setDeltaPOC (i, - pcSlice->getPOC() + longtermPicsPoc[ctr]); + rps->setUsed (i, tempArray[ctr]); + rps->setPocLSBLT (i, longtermPicsLSB[ctr]); + rps->setDeltaPocMSBCycleLT (i, (currMSB - (longtermPicsPoc[ctr] - longtermPicsLSB[ctr])) / maxPicOrderCntLSB); + rps->setDeltaPocMSBPresentFlag(i, mSBPresentFlag[ctr]); + + assert(rps->getDeltaPocMSBCycleLT(i) >= 0); // Non-negative value + } + for(i = rps->getNumberOfPictures() - 1, ctr = 1; i >= offset; i--, ctr++) + { + for(Int j = rps->getNumberOfPictures() - 1 - ctr; j >= offset; j--) + { + // Here at the encoder we know that we have set the full POC value for the LTRPs, hence we + // don't have to check the MSB present flag values for this constraint. + assert( rps->getPOC(i) != rps->getPOC(j) ); // If assert fails, LTRP entry repeated in RPS!!! + } + } +} + +/** Function for finding the position to insert the first of APS and non-nested BP, PT, DU info SEI messages. + * \param accessUnit Access Unit of the current picture + * This function finds the position to insert the first of APS and non-nested BP, PT, DU info SEI messages. + */ +Int TEncGOP::xGetFirstSeiLocation(AccessUnit &accessUnit) +{ + // Find the location of the first SEI message + Int seiStartPos = 0; + for(AccessUnit::iterator it = accessUnit.begin(); it != accessUnit.end(); it++, seiStartPos++) + { + if ((*it)->isSei() || (*it)->isVcl()) + { + break; + } + } + // assert(it != accessUnit.end()); // Triggers with some legit configurations + return seiStartPos; +} + +Void TEncGOP::dblMetric( TComPic* pcPic, UInt uiNumSlices ) +{ + TComPicYuv* pcPicYuvRec = pcPic->getPicYuvRec(); + Pel* Rec = pcPicYuvRec->getAddr(COMPONENT_Y); + Pel* tempRec = Rec; + Int stride = pcPicYuvRec->getStride(COMPONENT_Y); + UInt log2maxTB = pcPic->getSlice(0)->getSPS()->getQuadtreeTULog2MaxSize(); + UInt maxTBsize = (1<getWidth(COMPONENT_Y); + const UInt picHeight = pcPicYuvRec->getHeight(COMPONENT_Y); + const UInt noCol = (picWidth>>log2maxTB); + const UInt noRows = (picHeight>>log2maxTB); + assert(noCol > 1); + assert(noRows > 1); + UInt64 *colSAD = (UInt64*)malloc(noCol*sizeof(UInt64)); + UInt64 *rowSAD = (UInt64*)malloc(noRows*sizeof(UInt64)); + UInt colIdx = 0; + UInt rowIdx = 0; + Pel p0, p1, p2, q0, q1, q2; + + Int qp = pcPic->getSlice(0)->getSliceQp(); + Int bitdepthScale = 1 << (g_bitDepth[CHANNEL_TYPE_LUMA]-8); + Int beta = TComLoopFilter::getBeta( qp ) * bitdepthScale; + const Int thr2 = (beta>>2); + const Int thr1 = 2*bitdepthScale; + UInt a = 0; + + memset(colSAD, 0, noCol*sizeof(UInt64)); + memset(rowSAD, 0, noRows*sizeof(UInt64)); + + if (maxTBsize > minBlockArtSize) + { + // Analyze vertical artifact edges + for(Int c = maxTBsize; c < picWidth; c += maxTBsize) + { + for(Int r = 0; r < picHeight; r++) + { + p2 = Rec[c-3]; + p1 = Rec[c-2]; + p0 = Rec[c-1]; + q0 = Rec[c]; + q1 = Rec[c+1]; + q2 = Rec[c+2]; + a = ((abs(p2-(p1<<1)+p0)+abs(q0-(q1<<1)+q2))<<1); + if ( thr1 < a && a < thr2) + { + colSAD[colIdx] += abs(p0 - q0); + } + Rec += stride; + } + colIdx++; + Rec = tempRec; + } + + // Analyze horizontal artifact edges + for(Int r = maxTBsize; r < picHeight; r += maxTBsize) + { + for(Int c = 0; c < picWidth; c++) + { + p2 = Rec[c + (r-3)*stride]; + p1 = Rec[c + (r-2)*stride]; + p0 = Rec[c + (r-1)*stride]; + q0 = Rec[c + r*stride]; + q1 = Rec[c + (r+1)*stride]; + q2 = Rec[c + (r+2)*stride]; + a = ((abs(p2-(p1<<1)+p0)+abs(q0-(q1<<1)+q2))<<1); + if (thr1 < a && a < thr2) + { + rowSAD[rowIdx] += abs(p0 - q0); + } + } + rowIdx++; + } + } + + UInt64 colSADsum = 0; + UInt64 rowSADsum = 0; + for(Int c = 0; c < noCol-1; c++) + { + colSADsum += colSAD[c]; + } + for(Int r = 0; r < noRows-1; r++) + { + rowSADsum += rowSAD[r]; + } + + colSADsum <<= 10; + rowSADsum <<= 10; + colSADsum /= (noCol-1); + colSADsum /= picHeight; + rowSADsum /= (noRows-1); + rowSADsum /= picWidth; + + UInt64 avgSAD = ((colSADsum + rowSADsum)>>1); + avgSAD >>= (g_bitDepth[CHANNEL_TYPE_LUMA]-8); + + if ( avgSAD > 2048 ) + { + avgSAD >>= 9; + Int offset = Clip3(2,6,(Int)avgSAD); + for (Int i=0; igetSlice(i)->setDeblockingFilterOverrideFlag(true); + pcPic->getSlice(i)->setDeblockingFilterDisable(false); + pcPic->getSlice(i)->setDeblockingFilterBetaOffsetDiv2( offset ); + pcPic->getSlice(i)->setDeblockingFilterTcOffsetDiv2( offset ); + } + } + else + { + for (Int i=0; igetSlice(i)->setDeblockingFilterOverrideFlag(false); + pcPic->getSlice(i)->setDeblockingFilterDisable( pcPic->getSlice(i)->getPPS()->getPicDisableDeblockingFilterFlag() ); + pcPic->getSlice(i)->setDeblockingFilterBetaOffsetDiv2( pcPic->getSlice(i)->getPPS()->getDeblockingFilterBetaOffsetDiv2() ); + pcPic->getSlice(i)->setDeblockingFilterTcOffsetDiv2( pcPic->getSlice(i)->getPPS()->getDeblockingFilterTcOffsetDiv2() ); + } + } + + free(colSAD); + free(rowSAD); +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncGOP.h b/jctvc/TLibEncoder/TEncGOP.h new file mode 100644 index 0000000..a822c4b --- /dev/null +++ b/jctvc/TLibEncoder/TEncGOP.h @@ -0,0 +1,193 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncGOP.h + \brief GOP encoder class (header) +*/ + +#ifndef __TENCGOP__ +#define __TENCGOP__ + +#include + +#include + +#include "TLibCommon/TComList.h" +#include "TLibCommon/TComPic.h" +#include "TLibCommon/TComBitCounter.h" +#include "TLibCommon/TComLoopFilter.h" +#include "TLibCommon/AccessUnit.h" +#include "TEncSampleAdaptiveOffset.h" +#include "TEncSlice.h" +#include "TEncEntropy.h" +#include "TEncCavlc.h" +#include "TEncSbac.h" +#include "SEIwrite.h" + +#include "TEncAnalyze.h" +#include "TEncRateCtrl.h" +#include + +//! \ingroup TLibEncoder +//! \{ + +class TEncTop; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +class TEncGOP +{ +private: + // Data + Bool m_bLongtermTestPictureHasBeenCoded; + Bool m_bLongtermTestPictureHasBeenCoded2; + UInt m_numLongTermRefPicSPS; + UInt m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS]; + Bool m_ltRefPicUsedByCurrPicFlag[MAX_NUM_LONG_TERM_REF_PICS]; + Int m_iLastIDR; + Int m_iGopSize; + Int m_iNumPicCoded; + Bool m_bFirst; +#if ALLOW_RECOVERY_POINT_AS_RAP + Int m_iLastRecoveryPicPOC; +#endif + + // Access channel + TEncTop* m_pcEncTop; + TEncCfg* m_pcCfg; + TEncSlice* m_pcSliceEncoder; + TComList* m_pcListPic; + + TEncEntropy* m_pcEntropyCoder; + TEncCavlc* m_pcCavlcCoder; + TEncSbac* m_pcSbacCoder; + TEncBinCABAC* m_pcBinCABAC; + TComLoopFilter* m_pcLoopFilter; + + SEIWriter m_seiWriter; + + //--Adaptive Loop filter + TEncSampleAdaptiveOffset* m_pcSAO; + TEncRateCtrl* m_pcRateCtrl; + // indicate sequence first + Bool m_bSeqFirst; + + // clean decoding refresh + Bool m_bRefreshPending; + Int m_pocCRA; + NalUnitType m_associatedIRAPType; + Int m_associatedIRAPPOC; + + std::vector m_vRVM_RP; + UInt m_lastBPSEI; + UInt m_totalCoded; + UInt m_cpbRemovalDelay; + UInt m_tl0Idx; + UInt m_rapIdx; + Bool m_activeParameterSetSEIPresentInAU; + Bool m_bufferingPeriodSEIPresentInAU; + Bool m_pictureTimingSEIPresentInAU; + Bool m_nestedBufferingPeriodSEIPresentInAU; + Bool m_nestedPictureTimingSEIPresentInAU; +public: + TEncGOP(); + virtual ~TEncGOP(); + + Void create (); + Void destroy (); + + Void init ( TEncTop* pcTEncTop ); + Void compressGOP ( Int iPOCLast, Int iNumPicRcvd, TComList& rcListPic, TComList& rcListPicYuvRec, + std::list& accessUnitsInGOP, Bool isField, Bool isTff, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE ); + Void xAttachSliceDataToNalUnit (OutputNALUnit& rNalu, TComOutputBitstream* pcBitstreamRedirect); + + + Int getGOPSize() { return m_iGopSize; } + + TComList* getListPic() { return m_pcListPic; } + + Void printOutSummary ( UInt uiNumAllPicCoded, Bool isField, const Bool printMSEBasedSNR, const Bool printSequenceMSE ); + Void preLoopFilterPicAll ( TComPic* pcPic, UInt64& ruiDist ); + + TEncSlice* getSliceEncoder() { return m_pcSliceEncoder; } + NalUnitType getNalUnitType( Int pocCurr, Int lastIdr, Bool isField ); + Void arrangeLongtermPicturesInRPS(TComSlice *, TComList& ); + +protected: + TEncRateCtrl* getRateCtrl() { return m_pcRateCtrl; } + +protected: + + Void xInitGOP ( Int iPOCLast, Int iNumPicRcvd, TComList& rcListPic, TComList& rcListPicYuvRecOut, Bool isField ); + Void xGetBuffer ( TComList& rcListPic, TComList& rcListPicYuvRecOut, Int iNumPicRcvd, Int iTimeOffset, TComPic*& rpcPic, TComPicYuv*& rpcPicYuvRecOut, Int pocCurr, Bool isField ); + + Void xCalculateAddPSNR ( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit&, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE ); + Void xCalculateInterlacedAddPSNR( TComPic* pcPicOrgFirstField, TComPic* pcPicOrgSecondField, + TComPicYuv* pcPicRecFirstField, TComPicYuv* pcPicRecSecondField, + const AccessUnit& accessUnit, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE ); + + UInt64 xFindDistortionFrame (TComPicYuv* pcPic0, TComPicYuv* pcPic1); + + Double xCalculateRVM(); + + SEIActiveParameterSets* xCreateSEIActiveParameterSets (TComSPS *sps); + SEIFramePacking* xCreateSEIFramePacking(); + SEISegmentedRectFramePacking* xCreateSEISegmentedRectFramePacking(); + SEIDisplayOrientation* xCreateSEIDisplayOrientation(); + SEIToneMappingInfo* xCreateSEIToneMappingInfo(); + SEITempMotionConstrainedTileSets* xCreateSEITempMotionConstrainedTileSets (); + SEIKneeFunctionInfo* xCreateSEIKneeFunctionInfo(); + SEIChromaSamplingFilterHint* xCreateSEIChromaSamplingFilterHint(Bool bChromaLocInfoPresent, Int iHorFilterIndex, Int iVerFilterIdc); + + Void xCreateLeadingSEIMessages (/*SEIMessages seiMessages,*/ AccessUnit &accessUnit, TComSPS *sps); + Int xGetFirstSeiLocation (AccessUnit &accessUnit); + Void xResetNonNestedSEIPresentFlags() + { + m_activeParameterSetSEIPresentInAU = false; + m_bufferingPeriodSEIPresentInAU = false; + m_pictureTimingSEIPresentInAU = false; + } + Void xResetNestedSEIPresentFlags() + { + m_nestedBufferingPeriodSEIPresentInAU = false; + m_nestedPictureTimingSEIPresentInAU = false; + } + Void dblMetric( TComPic* pcPic, UInt uiNumSlices ); +};// END CLASS DEFINITION TEncGOP + +//! \} + +#endif // __TENCGOP__ + diff --git a/jctvc/TLibEncoder/TEncPic.cpp b/jctvc/TLibEncoder/TEncPic.cpp new file mode 100644 index 0000000..8c28c57 --- /dev/null +++ b/jctvc/TLibEncoder/TEncPic.cpp @@ -0,0 +1,156 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncPic.cpp + \brief class of picture which includes side information for encoder +*/ + +#include "TEncPic.h" + +//! \ingroup TLibEncoder +//! \{ + +/** Constructor + */ +TEncQPAdaptationUnit::TEncQPAdaptationUnit() +: m_dActivity(0.0) +{ +} + +/** Destructor + */ +TEncQPAdaptationUnit::~TEncQPAdaptationUnit() +{ +} + +/** Constructor + */ +TEncPicQPAdaptationLayer::TEncPicQPAdaptationLayer() +: m_uiAQPartWidth(0) +, m_uiAQPartHeight(0) +, m_uiNumAQPartInWidth(0) +, m_uiNumAQPartInHeight(0) +, m_acTEncAQU(NULL) +, m_dAvgActivity(0.0) +{ +} + +/** Destructor + */ +TEncPicQPAdaptationLayer::~TEncPicQPAdaptationLayer() +{ + destroy(); +} + +/** Initialize member variables + * \param iWidth Picture width + * \param iHeight Picture height + * \param uiAQPartWidth Width of unit block for analyzing local image characteristics + * \param uiAQPartHeight Height of unit block for analyzing local image characteristics + * \return Void + */ +Void TEncPicQPAdaptationLayer::create( Int iWidth, Int iHeight, UInt uiAQPartWidth, UInt uiAQPartHeight ) +{ + m_uiAQPartWidth = uiAQPartWidth; + m_uiAQPartHeight = uiAQPartHeight; + m_uiNumAQPartInWidth = (iWidth + m_uiAQPartWidth-1) / m_uiAQPartWidth; + m_uiNumAQPartInHeight = (iHeight + m_uiAQPartHeight-1) / m_uiAQPartHeight; + m_acTEncAQU = new TEncQPAdaptationUnit[ m_uiNumAQPartInWidth * m_uiNumAQPartInHeight ]; +} + +/** Clean up + * \return Void + */ +Void TEncPicQPAdaptationLayer::destroy() +{ + if (m_acTEncAQU) + { + delete[] m_acTEncAQU; + m_acTEncAQU = NULL; + } +} + +/** Constructor + */ +TEncPic::TEncPic() +: m_acAQLayer(NULL) +, m_uiMaxAQDepth(0) +{ +} + +/** Destructor + */ +TEncPic::~TEncPic() +{ + destroy(); +} + +/** Initialize member variables + * \param iWidth Picture width + * \param iHeight Picture height + * \param uiMaxWidth Maximum CU width + * \param uiMaxHeight Maximum CU height + * \param uiMaxDepth Maximum CU depth + * \param uiMaxAQDepth Maximum depth of unit block for assigning QP adaptive to local image characteristics + * \param bIsVirtual + * \return Void + */ +Void TEncPic::create( Int iWidth, Int iHeight, ChromaFormat chromaFormat, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, UInt uiMaxAQDepth, + Window &conformanceWindow, Window &defaultDisplayWindow, Int *numReorderPics, Bool bIsVirtual ) +{ + TComPic::create( iWidth, iHeight, chromaFormat, uiMaxWidth, uiMaxHeight, uiMaxDepth, conformanceWindow, defaultDisplayWindow, numReorderPics, bIsVirtual ); + m_uiMaxAQDepth = uiMaxAQDepth; + if ( uiMaxAQDepth > 0 ) + { + m_acAQLayer = new TEncPicQPAdaptationLayer[ m_uiMaxAQDepth ]; + for (UInt d = 0; d < m_uiMaxAQDepth; d++) + { + m_acAQLayer[d].create( iWidth, iHeight, uiMaxWidth>>d, uiMaxHeight>>d ); + } + } +} + +/** Clean up + * \return Void + */ +Void TEncPic::destroy() +{ + if (m_acAQLayer) + { + delete[] m_acAQLayer; + m_acAQLayer = NULL; + } + TComPic::destroy(); +} +//! \} + diff --git a/jctvc/TLibEncoder/TEncPic.h b/jctvc/TLibEncoder/TEncPic.h new file mode 100644 index 0000000..670530e --- /dev/null +++ b/jctvc/TLibEncoder/TEncPic.h @@ -0,0 +1,115 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncPic.h + \brief class of picture which includes side information for encoder (header) +*/ + +#ifndef __TENCPIC__ +#define __TENCPIC__ + +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComPic.h" + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// Unit block for storing image characteristics +class TEncQPAdaptationUnit +{ +private: + Double m_dActivity; + +public: + TEncQPAdaptationUnit(); + ~TEncQPAdaptationUnit(); + + Void setActivity( Double d ) { m_dActivity = d; } + Double getActivity() { return m_dActivity; } +}; + +/// Local image characteristics for CUs on a specific depth +class TEncPicQPAdaptationLayer +{ +private: + UInt m_uiAQPartWidth; + UInt m_uiAQPartHeight; + UInt m_uiNumAQPartInWidth; + UInt m_uiNumAQPartInHeight; + TEncQPAdaptationUnit* m_acTEncAQU; + Double m_dAvgActivity; + +public: + TEncPicQPAdaptationLayer(); + virtual ~TEncPicQPAdaptationLayer(); + + Void create( Int iWidth, Int iHeight, UInt uiAQPartWidth, UInt uiAQPartHeight ); + Void destroy(); + + UInt getAQPartWidth() { return m_uiAQPartWidth; } + UInt getAQPartHeight() { return m_uiAQPartHeight; } + UInt getNumAQPartInWidth() { return m_uiNumAQPartInWidth; } + UInt getNumAQPartInHeight() { return m_uiNumAQPartInHeight; } + UInt getAQPartStride() { return m_uiNumAQPartInWidth; } + TEncQPAdaptationUnit* getQPAdaptationUnit() { return m_acTEncAQU; } + Double getAvgActivity() { return m_dAvgActivity; } + + Void setAvgActivity( Double d ) { m_dAvgActivity = d; } +}; + +/// Picture class including local image characteristics information for QP adaptation +class TEncPic : public TComPic +{ +private: + TEncPicQPAdaptationLayer* m_acAQLayer; + UInt m_uiMaxAQDepth; + +public: + TEncPic(); + virtual ~TEncPic(); + + Void create( Int iWidth, Int iHeight, ChromaFormat chromaFormat, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, UInt uiMaxAQDepth, + Window &conformanceWindow, Window &defaultDisplayWindow, Int *numReorderPics, Bool bIsVirtual = false ); + virtual Void destroy(); + + TEncPicQPAdaptationLayer* getAQLayer( UInt uiDepth ) { return &m_acAQLayer[uiDepth]; } + UInt getMaxAQDepth() { return m_uiMaxAQDepth; } +}; + +//! \} + +#endif // __TENCPIC__ diff --git a/jctvc/TLibEncoder/TEncPreanalyzer.cpp b/jctvc/TLibEncoder/TEncPreanalyzer.cpp new file mode 100644 index 0000000..c2ed251 --- /dev/null +++ b/jctvc/TLibEncoder/TEncPreanalyzer.cpp @@ -0,0 +1,141 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncPreanalyzer.cpp + \brief source picture analyzer class +*/ + +#include +#include + +#include "TEncPreanalyzer.h" + +using namespace std; + +//! \ingroup TLibEncoder +//! \{ + +/** Constructor + */ +TEncPreanalyzer::TEncPreanalyzer() +{ +} + +/** Destructor + */ +TEncPreanalyzer::~TEncPreanalyzer() +{ +} + +/** Analyze source picture and compute local image characteristics used for QP adaptation + * \param pcEPic Picture object to be analyzed + * \return Void + */ +Void TEncPreanalyzer::xPreanalyze( TEncPic* pcEPic ) +{ + TComPicYuv* pcPicYuv = pcEPic->getPicYuvOrg(); + const Int iWidth = pcPicYuv->getWidth(COMPONENT_Y); + const Int iHeight = pcPicYuv->getHeight(COMPONENT_Y); + const Int iStride = pcPicYuv->getStride(COMPONENT_Y); + + for ( UInt d = 0; d < pcEPic->getMaxAQDepth(); d++ ) + { + const Pel* pLineY = pcPicYuv->getAddr(COMPONENT_Y); + TEncPicQPAdaptationLayer* pcAQLayer = pcEPic->getAQLayer(d); + const UInt uiAQPartWidth = pcAQLayer->getAQPartWidth(); + const UInt uiAQPartHeight = pcAQLayer->getAQPartHeight(); + TEncQPAdaptationUnit* pcAQU = pcAQLayer->getQPAdaptationUnit(); + + Double dSumAct = 0.0; + for ( UInt y = 0; y < iHeight; y += uiAQPartHeight ) + { + const UInt uiCurrAQPartHeight = min(uiAQPartHeight, iHeight-y); + for ( UInt x = 0; x < iWidth; x += uiAQPartWidth, pcAQU++ ) + { + const UInt uiCurrAQPartWidth = min(uiAQPartWidth, iWidth-x); + const Pel* pBlkY = &pLineY[x]; + UInt64 uiSum[4] = {0, 0, 0, 0}; + UInt64 uiSumSq[4] = {0, 0, 0, 0}; + UInt uiNumPixInAQPart = 0; + UInt by = 0; + for ( ; by < uiCurrAQPartHeight>>1; by++ ) + { + UInt bx = 0; + for ( ; bx < uiCurrAQPartWidth>>1; bx++, uiNumPixInAQPart++ ) + { + uiSum [0] += pBlkY[bx]; + uiSumSq[0] += pBlkY[bx] * pBlkY[bx]; + } + for ( ; bx < uiCurrAQPartWidth; bx++, uiNumPixInAQPart++ ) + { + uiSum [1] += pBlkY[bx]; + uiSumSq[1] += pBlkY[bx] * pBlkY[bx]; + } + pBlkY += iStride; + } + for ( ; by < uiCurrAQPartHeight; by++ ) + { + UInt bx = 0; + for ( ; bx < uiCurrAQPartWidth>>1; bx++, uiNumPixInAQPart++ ) + { + uiSum [2] += pBlkY[bx]; + uiSumSq[2] += pBlkY[bx] * pBlkY[bx]; + } + for ( ; bx < uiCurrAQPartWidth; bx++, uiNumPixInAQPart++ ) + { + uiSum [3] += pBlkY[bx]; + uiSumSq[3] += pBlkY[bx] * pBlkY[bx]; + } + pBlkY += iStride; + } + + Double dMinVar = DBL_MAX; + for ( Int i=0; i<4; i++) + { + const Double dAverage = Double(uiSum[i]) / uiNumPixInAQPart; + const Double dVariance = Double(uiSumSq[i]) / uiNumPixInAQPart - dAverage * dAverage; + dMinVar = min(dMinVar, dVariance); + } + const Double dActivity = 1.0 + dMinVar; + pcAQU->setActivity( dActivity ); + dSumAct += dActivity; + } + pLineY += iStride * uiCurrAQPartHeight; + } + + const Double dAvgAct = dSumAct / (pcAQLayer->getNumAQPartInWidth() * pcAQLayer->getNumAQPartInHeight()); + pcAQLayer->setAvgActivity( dAvgAct ); + } +} +//! \} + diff --git a/jctvc/TLibEncoder/TEncPreanalyzer.h b/jctvc/TLibEncoder/TEncPreanalyzer.h new file mode 100644 index 0000000..374191e --- /dev/null +++ b/jctvc/TLibEncoder/TEncPreanalyzer.h @@ -0,0 +1,62 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncPreanalyzer.h + \brief source picture analyzer class (header) +*/ + +#ifndef __TENCPREANALYZER__ +#define __TENCPREANALYZER__ + +#include "TEncPic.h" + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// Source picture analyzer class +class TEncPreanalyzer +{ +public: + TEncPreanalyzer(); + virtual ~TEncPreanalyzer(); + + Void xPreanalyze( TEncPic* pcPic ); +}; + +//! \} + +#endif // __TENCPREANALYZER__ diff --git a/jctvc/TLibEncoder/TEncRateCtrl.cpp b/jctvc/TLibEncoder/TEncRateCtrl.cpp new file mode 100644 index 0000000..878175c --- /dev/null +++ b/jctvc/TLibEncoder/TEncRateCtrl.cpp @@ -0,0 +1,1402 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncRateCtrl.cpp + \brief Rate control manager class +*/ +#include "TEncRateCtrl.h" +#include "../TLibCommon/TComPic.h" +#include "../TLibCommon/TComChromaFormat.h" + +#include + +using namespace std; + +//sequence level +TEncRCSeq::TEncRCSeq() +{ + m_totalFrames = 0; + m_targetRate = 0; + m_frameRate = 0; + m_targetBits = 0; + m_GOPSize = 0; + m_picWidth = 0; + m_picHeight = 0; + m_LCUWidth = 0; + m_LCUHeight = 0; + m_numberOfLevel = 0; + m_numberOfLCU = 0; + m_averageBits = 0; + m_bitsRatio = NULL; + m_GOPID2Level = NULL; + m_picPara = NULL; + m_LCUPara = NULL; + m_numberOfPixel = 0; + m_framesLeft = 0; + m_bitsLeft = 0; + m_useLCUSeparateModel = false; + m_adaptiveBit = 0; + m_lastLambda = 0.0; +} + +TEncRCSeq::~TEncRCSeq() +{ + destroy(); +} + +Void TEncRCSeq::create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit ) +{ + destroy(); + m_totalFrames = totalFrames; + m_targetRate = targetBitrate; + m_frameRate = frameRate; + m_GOPSize = GOPSize; + m_picWidth = picWidth; + m_picHeight = picHeight; + m_LCUWidth = LCUWidth; + m_LCUHeight = LCUHeight; + m_numberOfLevel = numberOfLevel; + m_useLCUSeparateModel = useLCUSeparateModel; + + m_numberOfPixel = m_picWidth * m_picHeight; + m_targetBits = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate; + m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel; + if ( m_seqTargetBpp < 0.03 ) + { + m_alphaUpdate = 0.01; + m_betaUpdate = 0.005; + } + else if ( m_seqTargetBpp < 0.08 ) + { + m_alphaUpdate = 0.05; + m_betaUpdate = 0.025; + } + else if ( m_seqTargetBpp < 0.2 ) + { + m_alphaUpdate = 0.1; + m_betaUpdate = 0.05; + } + else if ( m_seqTargetBpp < 0.5 ) + { + m_alphaUpdate = 0.2; + m_betaUpdate = 0.1; + } + else + { + m_alphaUpdate = 0.4; + m_betaUpdate = 0.2; + } + + m_averageBits = (Int)(m_targetBits / totalFrames); + Int picWidthInBU = ( m_picWidth % m_LCUWidth ) == 0 ? m_picWidth / m_LCUWidth : m_picWidth / m_LCUWidth + 1; + Int picHeightInBU = ( m_picHeight % m_LCUHeight ) == 0 ? m_picHeight / m_LCUHeight : m_picHeight / m_LCUHeight + 1; + m_numberOfLCU = picWidthInBU * picHeightInBU; + + m_bitsRatio = new Int[m_GOPSize]; + for ( Int i=0; i0) + { + m_picPara[i].m_alpha = 3.2003; + m_picPara[i].m_beta = -1.367; + } + else + { + m_picPara[i].m_alpha = ALPHA; + m_picPara[i].m_beta = BETA2; + } + } + } + else + { + for ( Int i=0; igetAdaptiveBits() > 0 && encRCSeq->getLastLambda() > 0.1 ) + { + Double targetBpp = (Double)targetBits / encRCSeq->getNumPixel(); + Double basicLambda = 0.0; + Double* lambdaRatio = new Double[encRCSeq->getGOPSize()]; + Double* equaCoeffA = new Double[encRCSeq->getGOPSize()]; + Double* equaCoeffB = new Double[encRCSeq->getGOPSize()]; + + if ( encRCSeq->getAdaptiveBits() == 1 ) // for GOP size =4, low delay case + { + if ( encRCSeq->getLastLambda() < 120.0 ) + { + lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.5793; + lambdaRatio[0] = 1.3 * lambdaRatio[1]; + lambdaRatio[2] = 1.3 * lambdaRatio[1]; + lambdaRatio[3] = 1.0; + } + else + { + lambdaRatio[0] = 5.0; + lambdaRatio[1] = 4.0; + lambdaRatio[2] = 5.0; + lambdaRatio[3] = 1.0; + } + } + else if ( encRCSeq->getAdaptiveBits() == 2 ) // for GOP size = 8, random access case + { + if ( encRCSeq->getLastLambda() < 90.0 ) + { + lambdaRatio[0] = 1.0; + lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.7963; + lambdaRatio[2] = 1.3 * lambdaRatio[1]; + lambdaRatio[3] = 3.25 * lambdaRatio[1]; + lambdaRatio[4] = 3.25 * lambdaRatio[1]; + lambdaRatio[5] = 1.3 * lambdaRatio[1]; + lambdaRatio[6] = 3.25 * lambdaRatio[1]; + lambdaRatio[7] = 3.25 * lambdaRatio[1]; + } + else + { + lambdaRatio[0] = 1.0; + lambdaRatio[1] = 4.0; + lambdaRatio[2] = 5.0; + lambdaRatio[3] = 12.3; + lambdaRatio[4] = 12.3; + lambdaRatio[5] = 5.0; + lambdaRatio[6] = 12.3; + lambdaRatio[7] = 12.3; + } + } + + xCalEquaCoeff( encRCSeq, lambdaRatio, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() ); + basicLambda = xSolveEqua( targetBpp, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() ); + encRCSeq->setAllBitRatio( basicLambda, equaCoeffA, equaCoeffB ); + + delete []lambdaRatio; + delete []equaCoeffA; + delete []equaCoeffB; + } + + m_picTargetBitInGOP = new Int[numPic]; + Int i; + Int totalPicRatio = 0; + Int currPicRatio = 0; + for ( i=0; igetBitRatio( i ); + } + for ( i=0; igetBitRatio( i ); + m_picTargetBitInGOP[i] = (Int)( ((Double)targetBits) * currPicRatio / totalPicRatio ); + } + + m_encRCSeq = encRCSeq; + m_numPic = numPic; + m_targetBits = targetBits; + m_picLeft = m_numPic; + m_bitsLeft = m_targetBits; +} + +Void TEncRCGOP::xCalEquaCoeff( TEncRCSeq* encRCSeq, Double* lambdaRatio, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize ) +{ + for ( Int i=0; igetGOPID2Level(i); + Double alpha = encRCSeq->getPicPara(frameLevel).m_alpha; + Double beta = encRCSeq->getPicPara(frameLevel).m_beta; + equaCoeffA[i] = pow( 1.0/alpha, 1.0/beta ) * pow( lambdaRatio[i], 1.0/beta ); + equaCoeffB[i] = 1.0/beta; + } +} + +Double TEncRCGOP::xSolveEqua( Double targetBpp, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize ) +{ + Double solution = 100.0; + Double minNumber = 0.1; + Double maxNumber = 10000.0; + for ( Int i=0; i targetBpp ) + { + minNumber = solution; + solution = ( solution + maxNumber ) / 2.0; + } + else + { + maxNumber = solution; + solution = ( solution + minNumber ) / 2.0; + } + } + + solution = Clip3( 0.1, 10000.0, solution ); + return solution; +} + +Void TEncRCGOP::destroy() +{ + m_encRCSeq = NULL; + if ( m_picTargetBitInGOP != NULL ) + { + delete[] m_picTargetBitInGOP; + m_picTargetBitInGOP = NULL; + } +} + +Void TEncRCGOP::updateAfterPicture( Int bitsCost ) +{ + m_bitsLeft -= bitsCost; + m_picLeft--; +} + +Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize ) +{ + Int realInfluencePicture = min( g_RCSmoothWindowSize, encRCSeq->getFramesLeft() ); + Int averageTargetBitsPerPic = (Int)( encRCSeq->getTargetBits() / encRCSeq->getTotalFrames() ); + Int currentTargetBitsPerPic = (Int)( ( encRCSeq->getBitsLeft() - averageTargetBitsPerPic * (encRCSeq->getFramesLeft() - realInfluencePicture) ) / realInfluencePicture ); + Int targetBits = currentTargetBitsPerPic * GOPSize; + + if ( targetBits < 200 ) + { + targetBits = 200; // at least allocate 200 bits for one GOP + } + + return targetBits; +} + +//picture level +TEncRCPic::TEncRCPic() +{ + m_encRCSeq = NULL; + m_encRCGOP = NULL; + + m_frameLevel = 0; + m_numberOfPixel = 0; + m_numberOfLCU = 0; + m_targetBits = 0; + m_estHeaderBits = 0; + m_estPicQP = 0; + m_estPicLambda = 0.0; + + m_LCULeft = 0; + m_bitsLeft = 0; + m_pixelsLeft = 0; + + m_LCUs = NULL; + m_picActualHeaderBits = 0; + m_picActualBits = 0; + m_picQP = 0; + m_picLambda = 0.0; +} + +TEncRCPic::~TEncRCPic() +{ + destroy(); +} + +Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP ) +{ + Int targetBits = 0; + Int GOPbitsLeft = encRCGOP->getBitsLeft(); + + Int i; + Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft(); + Int currPicRatio = encRCSeq->getBitRatio( currPicPosition ); + Int totalPicRatio = 0; + for ( i=currPicPosition; igetNumPic(); i++ ) + { + totalPicRatio += encRCSeq->getBitRatio( i ); + } + + targetBits = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio ); + + if ( targetBits < 100 ) + { + targetBits = 100; // at least allocate 100 bits for one picture + } + + if ( m_encRCSeq->getFramesLeft() > 16 ) + { + targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) ); + } + + return targetBits; +} + +Int TEncRCPic::xEstPicHeaderBits( list& listPreviousPictures, Int frameLevel ) +{ + Int numPreviousPics = 0; + Int totalPreviousBits = 0; + + list::iterator it; + for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) + { + if ( (*it)->getFrameLevel() == frameLevel ) + { + totalPreviousBits += (*it)->getPicActualHeaderBits(); + numPreviousPics++; + } + } + + Int estHeaderBits = 0; + if ( numPreviousPics > 0 ) + { + estHeaderBits = totalPreviousBits / numPreviousPics; + } + + return estHeaderBits; +} + +Void TEncRCPic::addToPictureLsit( list& listPreviousPictures ) +{ + if ( listPreviousPictures.size() > g_RCMaxPicListSize ) + { + TEncRCPic* p = listPreviousPictures.front(); + listPreviousPictures.pop_front(); + p->destroy(); + delete p; + } + + listPreviousPictures.push_back( this ); +} + +Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list& listPreviousPictures ) +{ + destroy(); + m_encRCSeq = encRCSeq; + m_encRCGOP = encRCGOP; + + Int targetBits = xEstPicTargetBits( encRCSeq, encRCGOP ); + Int estHeaderBits = xEstPicHeaderBits( listPreviousPictures, frameLevel ); + + if ( targetBits < estHeaderBits + 100 ) + { + targetBits = estHeaderBits + 100; // at least allocate 100 bits for picture data + } + + m_frameLevel = frameLevel; + m_numberOfPixel = encRCSeq->getNumPixel(); + m_numberOfLCU = encRCSeq->getNumberOfLCU(); + m_estPicLambda = 100.0; + m_targetBits = targetBits; + m_estHeaderBits = estHeaderBits; + m_bitsLeft = m_targetBits; + Int picWidth = encRCSeq->getPicWidth(); + Int picHeight = encRCSeq->getPicHeight(); + Int LCUWidth = encRCSeq->getLCUWidth(); + Int LCUHeight = encRCSeq->getLCUHeight(); + Int picWidthInLCU = ( picWidth % LCUWidth ) == 0 ? picWidth / LCUWidth : picWidth / LCUWidth + 1; + Int picHeightInLCU = ( picHeight % LCUHeight ) == 0 ? picHeight / LCUHeight : picHeight / LCUHeight + 1; + + m_LCULeft = m_numberOfLCU; + m_bitsLeft -= m_estHeaderBits; + m_pixelsLeft = m_numberOfPixel; + + m_LCUs = new TRCLCU[m_numberOfLCU]; + Int i, j; + Int LCUIdx; + for ( i=0; i& listPreviousPictures, SliceType eSliceType) +{ + Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; + Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; + Double bpp = (Double)m_targetBits/(Double)m_numberOfPixel; + Double estLambda; + if (eSliceType == I_SLICE) + { + estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp); + } + else + { + estLambda = alpha * pow( bpp, beta ); + } + + Double lastLevelLambda = -1.0; + Double lastPicLambda = -1.0; + Double lastValidLambda = -1.0; + list::iterator it; + for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) + { + if ( (*it)->getFrameLevel() == m_frameLevel ) + { + lastLevelLambda = (*it)->getPicActualLambda(); + } + lastPicLambda = (*it)->getPicActualLambda(); + + if ( lastPicLambda > 0.0 ) + { + lastValidLambda = lastPicLambda; + } + } + + if ( lastLevelLambda > 0.0 ) + { + lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda ); + estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda ); + } + + if ( lastPicLambda > 0.0 ) + { + lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda ); + estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda ); + } + else if ( lastValidLambda > 0.0 ) + { + lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda ); + estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda ); + } + else + { + estLambda = Clip3( 0.1, 10000.0, estLambda ); + } + + if ( estLambda < 0.1 ) + { + estLambda = 0.1; + } + + m_estPicLambda = estLambda; + + Double totalWeight = 0.0; + // initial BU bit allocation weight + for ( Int i=0; igetUseLCUSeparateModel() ) + { + alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha; + betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta; + } + else + { + alphaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; + betaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; + } + + m_LCUs[i].m_bitWeight = m_LCUs[i].m_numberOfPixel * pow( estLambda/alphaLCU, 1.0/betaLCU ); + + if ( m_LCUs[i].m_bitWeight < 0.01 ) + { + m_LCUs[i].m_bitWeight = 0.01; + } + totalWeight += m_LCUs[i].m_bitWeight; + } + for ( Int i=0; i& listPreviousPictures ) +{ + Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); + + Int lastLevelQP = g_RCInvalidQPValue; + Int lastPicQP = g_RCInvalidQPValue; + Int lastValidQP = g_RCInvalidQPValue; + list::iterator it; + for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) + { + if ( (*it)->getFrameLevel() == m_frameLevel ) + { + lastLevelQP = (*it)->getPicActualQP(); + } + lastPicQP = (*it)->getPicActualQP(); + if ( lastPicQP > g_RCInvalidQPValue ) + { + lastValidQP = lastPicQP; + } + } + + if ( lastLevelQP > g_RCInvalidQPValue ) + { + QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP ); + } + + if( lastPicQP > g_RCInvalidQPValue ) + { + QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP ); + } + else if( lastValidQP > g_RCInvalidQPValue ) + { + QP = Clip3( lastValidQP - 10, lastValidQP + 10, QP ); + } + + return QP; +} + +Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType) +{ + Int LCUIdx = getLCUCoded(); + Double bpp = -1.0; + Int avgBits = 0; + + if (eSliceType == I_SLICE) + { + Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1; + Int bitrateWindow = min(4,noOfLCUsLeft); + Double MAD = getLCU(LCUIdx).m_costIntra; + + if (m_remainingCostIntra > 0.1 ) + { + Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow; + avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra ); + } + else + { + avgBits = Int( m_bitsLeft / m_LCULeft ); + } + m_remainingCostIntra -= MAD; + } + else + { + Double totalWeight = 0; + for ( Int i=LCUIdx; igetUseLCUSeparateModel() ) + { + alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha; + beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta; + } + else + { + alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; + beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; + } + + Double estLambda = alpha * pow( bpp, beta ); + //for Lambda clip, picture level clip + Double clipPicLambda = m_estPicLambda; + + //for Lambda clip, LCU level clip + Double clipNeighbourLambda = -1.0; + for ( Int i=LCUIdx - 1; i>=0; i-- ) + { + if ( m_LCUs[i].m_lambda > 0 ) + { + clipNeighbourLambda = m_LCUs[i].m_lambda; + break; + } + } + + if ( clipNeighbourLambda > 0.0 ) + { + estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda ); + } + + if ( clipPicLambda > 0.0 ) + { + estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda ); + } + else + { + estLambda = Clip3( 10.0, 1000.0, estLambda ); + } + + if ( estLambda < 0.1 ) + { + estLambda = 0.1; + } + + return estLambda; +} + +Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP ) +{ + Int LCUIdx = getLCUCoded(); + Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); + + //for Lambda clip, LCU level clip + Int clipNeighbourQP = g_RCInvalidQPValue; + for ( Int i=LCUIdx - 1; i>=0; i-- ) + { + if ( (getLCU(i)).m_QP > g_RCInvalidQPValue ) + { + clipNeighbourQP = getLCU(i).m_QP; + break; + } + } + + if ( clipNeighbourQP > g_RCInvalidQPValue ) + { + estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP ); + } + + estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP ); + + return estQP; +} + +Void TEncRCPic::updateAfterCTU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter ) +{ + m_LCUs[LCUIdx].m_actualBits = bits; + m_LCUs[LCUIdx].m_QP = QP; + m_LCUs[LCUIdx].m_lambda = lambda; + + m_LCULeft--; + m_bitsLeft -= bits; + m_pixelsLeft -= m_LCUs[LCUIdx].m_numberOfPixel; + + if ( !updateLCUParameter ) + { + return; + } + + if ( !m_encRCSeq->getUseLCUSeparateModel() ) + { + return; + } + + Double alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha; + Double beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta; + + Int LCUActualBits = m_LCUs[LCUIdx].m_actualBits; + Int LCUTotalPixels = m_LCUs[LCUIdx].m_numberOfPixel; + Double bpp = ( Double )LCUActualBits/( Double )LCUTotalPixels; + Double calLambda = alpha * pow( bpp, beta ); + Double inputLambda = m_LCUs[LCUIdx].m_lambda; + + if( inputLambda < 0.01 || calLambda < 0.01 || bpp < 0.0001 ) + { + alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 ); + beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 ); + + alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); + beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); + + TRCParameter rcPara; + rcPara.m_alpha = alpha; + rcPara.m_beta = beta; + m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara ); + + return; + } + + calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda ); + alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha; + Double lnbpp = log( bpp ); + lnbpp = Clip3( -5.0, -0.1, lnbpp ); + beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp; + + alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); + beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); + + TRCParameter rcPara; + rcPara.m_alpha = alpha; + rcPara.m_beta = beta; + m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara ); + +} + +Double TEncRCPic::calAverageQP() +{ + Int totalQPs = 0; + Int numTotalLCUs = 0; + + Int i; + for ( i=0; i 0 ) + { + totalQPs += m_LCUs[i].m_QP; + numTotalLCUs++; + } + } + + Double avgQP = 0.0; + if ( numTotalLCUs == 0 ) + { + avgQP = g_RCInvalidQPValue; + } + else + { + avgQP = ((Double)totalQPs) / ((Double)numTotalLCUs); + } + return avgQP; +} + +Double TEncRCPic::calAverageLambda() +{ + Double totalLambdas = 0.0; + Int numTotalLCUs = 0; + + Int i; + for ( i=0; i 0.01 ) + { + totalLambdas += log( m_LCUs[i].m_lambda ); + numTotalLCUs++; + } + } + + Double avgLambda; + if( numTotalLCUs == 0 ) + { + avgLambda = -1.0; + } + else + { + avgLambda = pow( 2.7183, totalLambdas / numTotalLCUs ); + } + return avgLambda; +} + + +Void TEncRCPic::updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType) +{ + m_picActualHeaderBits = actualHeaderBits; + m_picActualBits = actualTotalBits; + if ( averageQP > 0.0 ) + { + m_picQP = Int( averageQP + 0.5 ); + } + else + { + m_picQP = g_RCInvalidQPValue; + } + m_picLambda = averageLambda; + + Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; + Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; + + if (eSliceType == I_SLICE) + { + updateAlphaBetaIntra(&alpha, &beta); + } + else + { + // update parameters + Double picActualBits = ( Double )m_picActualBits; + Double picActualBpp = picActualBits/(Double)m_numberOfPixel; + Double calLambda = alpha * pow( picActualBpp, beta ); + Double inputLambda = m_picLambda; + + if ( inputLambda < 0.01 || calLambda < 0.01 || picActualBpp < 0.0001 ) + { + alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 ); + beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 ); + + alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); + beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); + + TRCParameter rcPara; + rcPara.m_alpha = alpha; + rcPara.m_beta = beta; + m_encRCSeq->setPicPara( m_frameLevel, rcPara ); + + return; + } + + calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda ); + alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha; + Double lnbpp = log( picActualBpp ); + lnbpp = Clip3( -5.0, -0.1, lnbpp ); + + beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp; + + alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); + beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); + } + + TRCParameter rcPara; + rcPara.m_alpha = alpha; + rcPara.m_beta = beta; + + m_encRCSeq->setPicPara( m_frameLevel, rcPara ); + + if ( m_frameLevel == 1 ) + { + Double currLambda = Clip3( 0.1, 10000.0, m_picLambda ); + Double updateLastLambda = g_RCWeightHistoryLambda * m_encRCSeq->getLastLambda() + g_RCWeightCurrentLambda * currLambda; + m_encRCSeq->setLastLambda( updateLastLambda ); + } +} + +Int TEncRCPic::getRefineBitsForIntra( Int orgBits ) +{ + Double alpha=0.25, beta=0.5582; + Int iIntraBits; + + if (orgBits*40 < m_numberOfPixel) + { + alpha=0.25; + } + else + { + alpha=0.30; + } + + iIntraBits = (Int)(alpha* pow(m_totalCostIntra*4.0/(Double)orgBits, beta)*(Double)orgBits+0.5); + + return iIntraBits; +} + +Double TEncRCPic::calculateLambdaIntra(Double alpha, Double beta, Double MADPerPixel, Double bitsPerPixel) +{ + return ( (alpha/256.0) * pow( MADPerPixel/bitsPerPixel, beta ) ); +} + +Void TEncRCPic::updateAlphaBetaIntra(Double *alpha, Double *beta) +{ + Double lnbpp = log(pow(m_totalCostIntra / (Double)m_numberOfPixel, BETA1)); + Double diffLambda = (*beta)*(log((Double)m_picActualBits)-log((Double)m_targetBits)); + + diffLambda = Clip3(-0.125, 0.125, 0.25*diffLambda); + *alpha = (*alpha) * exp(diffLambda); + *beta = (*beta) + diffLambda / lnbpp; +} + + +Void TEncRCPic::getLCUInitTargetBits() +{ + Int iAvgBits = 0; + + m_remainingCostIntra = m_totalCostIntra; + for (Int i=m_numberOfLCU-1; i>=0; i--) + { + iAvgBits += Int(m_targetBits * getLCU(i).m_costIntra/m_totalCostIntra); + getLCU(i).m_targetBitsLeft = iAvgBits; + } +} + + +Double TEncRCPic::getLCUEstLambdaAndQP(Double bpp, Int clipPicQP, Int *estQP) +{ + Int LCUIdx = getLCUCoded(); + + Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; + Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; + + Double costPerPixel = getLCU(LCUIdx).m_costIntra/(Double)getLCU(LCUIdx).m_numberOfPixel; + costPerPixel = pow(costPerPixel, BETA1); + Double estLambda = calculateLambdaIntra(alpha, beta, costPerPixel, bpp); + + Int clipNeighbourQP = g_RCInvalidQPValue; + for (Int i=LCUIdx-1; i>=0; i--) + { + if ((getLCU(i)).m_QP > g_RCInvalidQPValue) + { + clipNeighbourQP = getLCU(i).m_QP; + break; + } + } + + Int minQP = clipPicQP - 2; + Int maxQP = clipPicQP + 2; + + if ( clipNeighbourQP > g_RCInvalidQPValue ) + { + maxQP = min(clipNeighbourQP + 1, maxQP); + minQP = max(clipNeighbourQP - 1, minQP); + } + + Double maxLambda=exp(((Double)(maxQP+0.49)-13.7122)/4.2005); + Double minLambda=exp(((Double)(minQP-0.49)-13.7122)/4.2005); + + estLambda = Clip3(minLambda, maxLambda, estLambda); + + *estQP = Int( 4.2005 * log(estLambda) + 13.7122 + 0.5 ); + *estQP = Clip3(minQP, maxQP, *estQP); + + return estLambda; +} + +TEncRateCtrl::TEncRateCtrl() +{ + m_encRCSeq = NULL; + m_encRCGOP = NULL; + m_encRCPic = NULL; +} + +TEncRateCtrl::~TEncRateCtrl() +{ + destroy(); +} + +Void TEncRateCtrl::destroy() +{ + if ( m_encRCSeq != NULL ) + { + delete m_encRCSeq; + m_encRCSeq = NULL; + } + if ( m_encRCGOP != NULL ) + { + delete m_encRCGOP; + m_encRCGOP = NULL; + } + while ( m_listRCPictures.size() > 0 ) + { + TEncRCPic* p = m_listRCPictures.front(); + m_listRCPictures.pop_front(); + delete p; + } +} + +Void TEncRateCtrl::init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] ) +{ + destroy(); + + Bool isLowdelay = true; + for ( Int i=0; i GOPList[i+1].m_POC ) + { + isLowdelay = false; + break; + } + } + + Int numberOfLevel = 1; + Int adaptiveBit = 0; + if ( keepHierBits > 0 ) + { + numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1; + } + if ( !isLowdelay && GOPSize == 8 ) + { + numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1; + } + numberOfLevel++; // intra picture + numberOfLevel++; // non-reference picture + + + Int* bitsRatio; + bitsRatio = new Int[ GOPSize ]; + for ( Int i=0; i 0 ) + { + Double bpp = (Double)( targetBitrate / (Double)( frameRate*picWidth*picHeight ) ); + if ( GOPSize == 4 && isLowdelay ) + { + if ( bpp > 0.2 ) + { + bitsRatio[0] = 2; + bitsRatio[1] = 3; + bitsRatio[2] = 2; + bitsRatio[3] = 6; + } + else if( bpp > 0.1 ) + { + bitsRatio[0] = 2; + bitsRatio[1] = 3; + bitsRatio[2] = 2; + bitsRatio[3] = 10; + } + else if ( bpp > 0.05 ) + { + bitsRatio[0] = 2; + bitsRatio[1] = 3; + bitsRatio[2] = 2; + bitsRatio[3] = 12; + } + else + { + bitsRatio[0] = 2; + bitsRatio[1] = 3; + bitsRatio[2] = 2; + bitsRatio[3] = 14; + } + + if ( keepHierBits == 2 ) + { + adaptiveBit = 1; + } + } + else if ( GOPSize == 8 && !isLowdelay ) + { + if ( bpp > 0.2 ) + { + bitsRatio[0] = 15; + bitsRatio[1] = 5; + bitsRatio[2] = 4; + bitsRatio[3] = 1; + bitsRatio[4] = 1; + bitsRatio[5] = 4; + bitsRatio[6] = 1; + bitsRatio[7] = 1; + } + else if ( bpp > 0.1 ) + { + bitsRatio[0] = 20; + bitsRatio[1] = 6; + bitsRatio[2] = 4; + bitsRatio[3] = 1; + bitsRatio[4] = 1; + bitsRatio[5] = 4; + bitsRatio[6] = 1; + bitsRatio[7] = 1; + } + else if ( bpp > 0.05 ) + { + bitsRatio[0] = 25; + bitsRatio[1] = 7; + bitsRatio[2] = 4; + bitsRatio[3] = 1; + bitsRatio[4] = 1; + bitsRatio[5] = 4; + bitsRatio[6] = 1; + bitsRatio[7] = 1; + } + else + { + bitsRatio[0] = 30; + bitsRatio[1] = 8; + bitsRatio[2] = 4; + bitsRatio[3] = 1; + bitsRatio[4] = 1; + bitsRatio[5] = 4; + bitsRatio[6] = 1; + bitsRatio[7] = 1; + } + + if ( keepHierBits == 2 ) + { + adaptiveBit = 2; + } + } + else + { + printf( "\n hierarchical bit allocation is not support for the specified coding structure currently.\n" ); + } + } + + Int* GOPID2Level = new Int[ GOPSize ]; + for ( Int i=0; i 0 ) + { + if ( GOPSize == 4 && isLowdelay ) + { + GOPID2Level[0] = 3; + GOPID2Level[1] = 2; + GOPID2Level[2] = 3; + GOPID2Level[3] = 1; + } + else if ( GOPSize == 8 && !isLowdelay ) + { + GOPID2Level[0] = 1; + GOPID2Level[1] = 2; + GOPID2Level[2] = 3; + GOPID2Level[3] = 4; + GOPID2Level[4] = 4; + GOPID2Level[5] = 3; + GOPID2Level[6] = 4; + GOPID2Level[7] = 4; + } + } + + if ( !isLowdelay && GOPSize == 8 ) + { + GOPID2Level[0] = 1; + GOPID2Level[1] = 2; + GOPID2Level[2] = 3; + GOPID2Level[3] = 4; + GOPID2Level[4] = 4; + GOPID2Level[5] = 3; + GOPID2Level[6] = 4; + GOPID2Level[7] = 4; + } + + m_encRCSeq = new TEncRCSeq; + m_encRCSeq->create( totalFrames, targetBitrate, frameRate, GOPSize, picWidth, picHeight, LCUWidth, LCUHeight, numberOfLevel, useLCUSeparateModel, adaptiveBit ); + m_encRCSeq->initBitsRatio( bitsRatio ); + m_encRCSeq->initGOPID2Level( GOPID2Level ); + m_encRCSeq->initPicPara(); + if ( useLCUSeparateModel ) + { + m_encRCSeq->initLCUPara(); + } + + delete[] bitsRatio; + delete[] GOPID2Level; +} + +Void TEncRateCtrl::initRCPic( Int frameLevel ) +{ + m_encRCPic = new TEncRCPic; + m_encRCPic->create( m_encRCSeq, m_encRCGOP, frameLevel, m_listRCPictures ); +} + +Void TEncRateCtrl::initRCGOP( Int numberOfPictures ) +{ + m_encRCGOP = new TEncRCGOP; + m_encRCGOP->create( m_encRCSeq, numberOfPictures ); +} + +Void TEncRateCtrl::destroyRCGOP() +{ + delete m_encRCGOP; + m_encRCGOP = NULL; +} diff --git a/jctvc/TLibEncoder/TEncRateCtrl.h b/jctvc/TLibEncoder/TEncRateCtrl.h new file mode 100644 index 0000000..6253e9d --- /dev/null +++ b/jctvc/TLibEncoder/TEncRateCtrl.h @@ -0,0 +1,335 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncRateCtrl.h + \brief Rate control manager class +*/ + +#ifndef __TENCRATECTRL__ +#define __TENCRATECTRL__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include "../TLibCommon/CommonDef.h" +#include "../TLibCommon/TComDataCU.h" + +#include +#include + +using namespace std; + +//! \ingroup TLibEncoder +//! \{ + +#include "../TLibEncoder/TEncCfg.h" +#include +#include + +const Int g_RCInvalidQPValue = -999; +const Int g_RCSmoothWindowSize = 40; +const Int g_RCMaxPicListSize = 32; +const Double g_RCWeightPicTargetBitInGOP = 0.9; +const Double g_RCWeightPicRargetBitInBuffer = 1.0 - g_RCWeightPicTargetBitInGOP; +const Int g_RCIterationNum = 20; +const Double g_RCWeightHistoryLambda = 0.5; +const Double g_RCWeightCurrentLambda = 1.0 - g_RCWeightHistoryLambda; +const Int g_RCLCUSmoothWindowSize = 4; +const Double g_RCAlphaMinValue = 0.05; +const Double g_RCAlphaMaxValue = 500.0; +const Double g_RCBetaMinValue = -3.0; +const Double g_RCBetaMaxValue = -0.1; + +#define ALPHA 6.7542; +#define BETA1 1.2517 +#define BETA2 1.7860 + +struct TRCLCU +{ + Int m_actualBits; + Int m_QP; // QP of skip mode is set to g_RCInvalidQPValue + Int m_targetBits; + Double m_lambda; + Double m_bitWeight; + Int m_numberOfPixel; + Double m_costIntra; + Int m_targetBitsLeft; +}; + +struct TRCParameter +{ + Double m_alpha; + Double m_beta; +}; + +class TEncRCSeq +{ +public: + TEncRCSeq(); + ~TEncRCSeq(); + +public: + Void create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit ); + Void destroy(); + Void initBitsRatio( Int bitsRatio[] ); + Void initGOPID2Level( Int GOPID2Level[] ); + Void initPicPara( TRCParameter* picPara = NULL ); // NULL to initial with default value + Void initLCUPara( TRCParameter** LCUPara = NULL ); // NULL to initial with default value + Void updateAfterPic ( Int bits ); + Void setAllBitRatio( Double basicLambda, Double* equaCoeffA, Double* equaCoeffB ); + +public: + Int getTotalFrames() { return m_totalFrames; } + Int getTargetRate() { return m_targetRate; } + Int getFrameRate() { return m_frameRate; } + Int getGOPSize() { return m_GOPSize; } + Int getPicWidth() { return m_picWidth; } + Int getPicHeight() { return m_picHeight; } + Int getLCUWidth() { return m_LCUWidth; } + Int getLCUHeight() { return m_LCUHeight; } + Int getNumberOfLevel() { return m_numberOfLevel; } + Int getAverageBits() { return m_averageBits; } + Int getLeftAverageBits() { assert( m_framesLeft > 0 ); return (Int)(m_bitsLeft / m_framesLeft); } + Bool getUseLCUSeparateModel() { return m_useLCUSeparateModel; } + + Int getNumPixel() { return m_numberOfPixel; } + Int64 getTargetBits() { return m_targetBits; } + Int getNumberOfLCU() { return m_numberOfLCU; } + Int* getBitRatio() { return m_bitsRatio; } + Int getBitRatio( Int idx ) { assert( idx& listPreviousPictures ); + Void destroy(); + + Int estimatePicQP ( Double lambda, list& listPreviousPictures ); + Int getRefineBitsForIntra(Int orgBits); + Double calculateLambdaIntra(Double alpha, Double beta, Double MADPerPixel, Double bitsPerPixel); + Double estimatePicLambda( list& listPreviousPictures, SliceType eSliceType); + + Void updateAlphaBetaIntra(Double *alpha, Double *beta); + + Double getLCUTargetBpp(SliceType eSliceType); + Double getLCUEstLambdaAndQP(Double bpp, Int clipPicQP, Int *estQP); + Double getLCUEstLambda( Double bpp ); + Int getLCUEstQP( Double lambda, Int clipPicQP ); + + Void updateAfterCTU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter = true ); + Void updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType); + + Void addToPictureLsit( list& listPreviousPictures ); + Double calAverageQP(); + Double calAverageLambda(); + +private: + Int xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP ); + Int xEstPicHeaderBits( list& listPreviousPictures, Int frameLevel ); + +public: + TEncRCSeq* getRCSequence() { return m_encRCSeq; } + TEncRCGOP* getRCGOP() { return m_encRCGOP; } + + Int getFrameLevel() { return m_frameLevel; } + Int getNumberOfPixel() { return m_numberOfPixel; } + Int getNumberOfLCU() { return m_numberOfLCU; } + Int getTargetBits() { return m_targetBits; } + Int getEstHeaderBits() { return m_estHeaderBits; } + Int getLCULeft() { return m_LCULeft; } + Int getBitsLeft() { return m_bitsLeft; } + Int getPixelsLeft() { return m_pixelsLeft; } + Int getBitsCoded() { return m_targetBits - m_estHeaderBits - m_bitsLeft; } + Int getLCUCoded() { return m_numberOfLCU - m_LCULeft; } + TRCLCU* getLCU() { return m_LCUs; } + TRCLCU& getLCU( Int LCUIdx ) { return m_LCUs[LCUIdx]; } + Int getPicActualHeaderBits() { return m_picActualHeaderBits; } + Void setTargetBits( Int bits ) { m_targetBits = bits; m_bitsLeft = bits;} + Void setTotalIntraCost(Double cost) { m_totalCostIntra = cost; } + Void getLCUInitTargetBits(); + + Int getPicActualBits() { return m_picActualBits; } + Int getPicActualQP() { return m_picQP; } + Double getPicActualLambda() { return m_picLambda; } + Int getPicEstQP() { return m_estPicQP; } + Void setPicEstQP( Int QP ) { m_estPicQP = QP; } + Double getPicEstLambda() { return m_estPicLambda; } + Void setPicEstLambda( Double lambda ) { m_picLambda = lambda; } + +private: + TEncRCSeq* m_encRCSeq; + TEncRCGOP* m_encRCGOP; + + Int m_frameLevel; + Int m_numberOfPixel; + Int m_numberOfLCU; + Int m_targetBits; + Int m_estHeaderBits; + Int m_estPicQP; + Double m_estPicLambda; + + Int m_LCULeft; + Int m_bitsLeft; + Int m_pixelsLeft; + + TRCLCU* m_LCUs; + Int m_picActualHeaderBits; // only SH and potential APS + Double m_totalCostIntra; + Double m_remainingCostIntra; + Int m_picActualBits; // the whole picture, including header + Int m_picQP; // in integer form + Double m_picLambda; +}; + +class TEncRateCtrl +{ +public: + TEncRateCtrl(); + ~TEncRateCtrl(); + +public: + Void init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] ); + Void destroy(); + Void initRCPic( Int frameLevel ); + Void initRCGOP( Int numberOfPictures ); + Void destroyRCGOP(); + +public: + Void setRCQP ( Int QP ) { m_RCQP = QP; } + Int getRCQP () { return m_RCQP; } + TEncRCSeq* getRCSeq() { assert ( m_encRCSeq != NULL ); return m_encRCSeq; } + TEncRCGOP* getRCGOP() { assert ( m_encRCGOP != NULL ); return m_encRCGOP; } + TEncRCPic* getRCPic() { assert ( m_encRCPic != NULL ); return m_encRCPic; } + list& getPicList() { return m_listRCPictures; } + +private: + TEncRCSeq* m_encRCSeq; + TEncRCGOP* m_encRCGOP; + TEncRCPic* m_encRCPic; + list m_listRCPictures; + Int m_RCQP; +}; + +#endif + + diff --git a/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.cpp b/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.cpp new file mode 100644 index 0000000..62e5424 --- /dev/null +++ b/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.cpp @@ -0,0 +1,1362 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + \file TEncSampleAdaptiveOffset.cpp + \brief estimation part of sample adaptive offset class + */ +#include "TEncSampleAdaptiveOffset.h" +#include +#include +#include +#include + +//! \ingroup TLibEncoder +//! \{ + + +/** rounding with IBDI + * \param x + */ +inline Double xRoundIbdi2(Int bitDepth, Double x) +{ + return ((x)>0) ? (Int)(((Int)(x)+(1<<(bitDepth-8-1)))/(1<<(bitDepth-8))) : ((Int)(((Int)(x)-(1<<(bitDepth-8-1)))/(1<<(bitDepth-8)))); +} + +inline Double xRoundIbdi(Int bitDepth, Double x) +{ + return (bitDepth > 8 ? xRoundIbdi2(bitDepth, (x)) : ((x)>=0 ? ((Int)((x)+0.5)) : ((Int)((x)-0.5)))) ; +} + + +TEncSampleAdaptiveOffset::TEncSampleAdaptiveOffset() +{ + m_pppcRDSbacCoder = NULL; + m_pcRDGoOnSbacCoder = NULL; + m_pppcBinCoderCABAC = NULL; + m_statData = NULL; +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + m_preDBFstatData = NULL; +#endif +} + +TEncSampleAdaptiveOffset::~TEncSampleAdaptiveOffset() +{ + destroyEncData(); +} + +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK +Void TEncSampleAdaptiveOffset::createEncData(Bool isPreDBFSamplesUsed) +#else +Void TEncSampleAdaptiveOffset::createEncData() +#endif +{ + + //cabac coder for RDO + m_pppcRDSbacCoder = new TEncSbac* [NUM_SAO_CABACSTATE_LABELS]; +#if FAST_BIT_EST + m_pppcBinCoderCABAC = new TEncBinCABACCounter* [NUM_SAO_CABACSTATE_LABELS]; +#else + m_pppcBinCoderCABAC = new TEncBinCABAC* [NUM_SAO_CABACSTATE_LABELS]; +#endif + + for(Int cs=0; cs < NUM_SAO_CABACSTATE_LABELS; cs++) + { + m_pppcRDSbacCoder[cs] = new TEncSbac; +#if FAST_BIT_EST + m_pppcBinCoderCABAC[cs] = new TEncBinCABACCounter; +#else + m_pppcBinCoderCABAC[cs] = new TEncBinCABAC; +#endif + m_pppcRDSbacCoder [cs]->init( m_pppcBinCoderCABAC [cs] ); + } + + + //statistics + m_statData = new SAOStatData**[m_numCTUsPic]; + for(Int i=0; i< m_numCTUsPic; i++) + { + m_statData[i] = new SAOStatData*[MAX_NUM_COMPONENT]; + for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + m_statData[i][compIdx] = new SAOStatData[NUM_SAO_NEW_TYPES]; + } + } +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + if(isPreDBFSamplesUsed) + { + m_preDBFstatData = new SAOStatData**[m_numCTUsPic]; + for(Int i=0; i< m_numCTUsPic; i++) + { + m_preDBFstatData[i] = new SAOStatData*[MAX_NUM_COMPONENT]; + for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + m_preDBFstatData[i][compIdx] = new SAOStatData[NUM_SAO_NEW_TYPES]; + } + } + + } +#endif + +#if SAO_ENCODING_CHOICE + ::memset(m_saoDisabledRate, 0, sizeof(m_saoDisabledRate)); +#endif + + for(Int typeIdc=0; typeIdc < NUM_SAO_NEW_TYPES; typeIdc++) + { + m_skipLinesR[COMPONENT_Y ][typeIdc]= 5; + m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3; + + m_skipLinesB[COMPONENT_Y ][typeIdc]= 4; + m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2; + +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + if(isPreDBFSamplesUsed) + { + switch(typeIdc) + { + case SAO_TYPE_EO_0: + { + m_skipLinesR[COMPONENT_Y ][typeIdc]= 5; + m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3; + + m_skipLinesB[COMPONENT_Y ][typeIdc]= 3; + m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 1; + } + break; + case SAO_TYPE_EO_90: + { + m_skipLinesR[COMPONENT_Y ][typeIdc]= 4; + m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 2; + + m_skipLinesB[COMPONENT_Y ][typeIdc]= 4; + m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2; + } + break; + case SAO_TYPE_EO_135: + case SAO_TYPE_EO_45: + { + m_skipLinesR[COMPONENT_Y ][typeIdc]= 5; + m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3; + + m_skipLinesB[COMPONENT_Y ][typeIdc]= 4; + m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2; + } + break; + case SAO_TYPE_BO: + { + m_skipLinesR[COMPONENT_Y ][typeIdc]= 4; + m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 2; + + m_skipLinesB[COMPONENT_Y ][typeIdc]= 3; + m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 1; + } + break; + default: + { + printf("Not a supported type"); + assert(0); + exit(-1); + } + } + } +#endif + } + +} + +Void TEncSampleAdaptiveOffset::destroyEncData() +{ + if(m_pppcRDSbacCoder != NULL) + { + for (Int cs = 0; cs < NUM_SAO_CABACSTATE_LABELS; cs ++ ) + { + delete m_pppcRDSbacCoder[cs]; + } + delete[] m_pppcRDSbacCoder; m_pppcRDSbacCoder = NULL; + } + + if(m_pppcBinCoderCABAC != NULL) + { + for (Int cs = 0; cs < NUM_SAO_CABACSTATE_LABELS; cs ++ ) + { + delete m_pppcBinCoderCABAC[cs]; + } + delete[] m_pppcBinCoderCABAC; m_pppcBinCoderCABAC = NULL; + } + + if(m_statData != NULL) + { + for(Int i=0; i< m_numCTUsPic; i++) + { + for(Int compIdx=0; compIdx< MAX_NUM_COMPONENT; compIdx++) + { + delete[] m_statData[i][compIdx]; + } + delete[] m_statData[i]; + } + delete[] m_statData; m_statData = NULL; + } +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + if(m_preDBFstatData != NULL) + { + for(Int i=0; i< m_numCTUsPic; i++) + { + for(Int compIdx=0; compIdx< MAX_NUM_COMPONENT; compIdx++) + { + delete[] m_preDBFstatData[i][compIdx]; + } + delete[] m_preDBFstatData[i]; + } + delete[] m_preDBFstatData; m_preDBFstatData = NULL; + } + +#endif +} + +Void TEncSampleAdaptiveOffset::initRDOCabacCoder(TEncSbac* pcRDGoOnSbacCoder, TComSlice* pcSlice) +{ + m_pcRDGoOnSbacCoder = pcRDGoOnSbacCoder; + m_pcRDGoOnSbacCoder->setSlice(pcSlice); + m_pcRDGoOnSbacCoder->resetEntropy(); + m_pcRDGoOnSbacCoder->resetBits(); + + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[SAO_CABACSTATE_PIC_INIT]); +} + + + +Void TEncSampleAdaptiveOffset::SAOProcess(TComPic* pPic, Bool* sliceEnabled, const Double *lambdas +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isPreDBFSamplesUsed +#endif + ) +{ + TComPicYuv* orgYuv= pPic->getPicYuvOrg(); + TComPicYuv* resYuv= pPic->getPicYuvRec(); + memcpy(m_lambda, lambdas, sizeof(m_lambda)); + TComPicYuv* srcYuv = m_tempPicYuv; + resYuv->copyToPic(srcYuv); + srcYuv->setBorderExtension(false); + srcYuv->extendPicBorder(); + + //collect statistics + getStatistics(m_statData, orgYuv, srcYuv, pPic); +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + if(isPreDBFSamplesUsed) + { + addPreDBFStatistics(m_statData); + } +#endif + //slice on/off + decidePicParams(sliceEnabled, pPic->getSlice(0)->getDepth()); + + //block on/off + SAOBlkParam* reconParams = new SAOBlkParam[m_numCTUsPic]; //temporary parameter buffer for storing reconstructed SAO parameters + decideBlkParams(pPic, sliceEnabled, m_statData, srcYuv, resYuv, reconParams, pPic->getPicSym()->getSAOBlkParam()); + delete[] reconParams; +} + +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK +Void TEncSampleAdaptiveOffset::getPreDBFStatistics(TComPic* pPic) +{ + getStatistics(m_preDBFstatData, pPic->getPicYuvOrg(), pPic->getPicYuvRec(), pPic, true); +} + +Void TEncSampleAdaptiveOffset::addPreDBFStatistics(SAOStatData*** blkStats) +{ + for(Int n=0; n< m_numCTUsPic; n++) + { + for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + for(Int typeIdc=0; typeIdc < NUM_SAO_NEW_TYPES; typeIdc++) + { + blkStats[n][compIdx][typeIdc] += m_preDBFstatData[n][compIdx][typeIdc]; + } + } + } +} + +#endif + +Void TEncSampleAdaptiveOffset::getStatistics(SAOStatData*** blkStats, TComPicYuv* orgYuv, TComPicYuv* srcYuv, TComPic* pPic +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isCalculatePreDeblockSamples +#endif + ) +{ + Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail; + + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + + for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++) + { + Int yPos = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight; + Int xPos = (ctuRsAddr % m_numCTUInWidth)*m_maxCUWidth; + Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight; + Int width = (xPos + m_maxCUWidth > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth; + + pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail); + + //NOTE: The number of skipped lines during gathering CTU statistics depends on the slice boundary availabilities. + //For simplicity, here only picture boundaries are considered. + + isRightAvail = (xPos + m_maxCUWidth < m_picWidth ); + isBelowAvail = (yPos + m_maxCUHeight < m_picHeight); + isBelowRightAvail = (isRightAvail && isBelowAvail); + isBelowLeftAvail = ((xPos > 0) && (isBelowAvail)); + isAboveRightAvail = ((yPos > 0) && (isRightAvail)); + + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + const ComponentID component = ComponentID(compIdx); + + const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat()); + const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat()); + + Int srcStride = srcYuv->getStride(component); + Pel* srcBlk = srcYuv->getAddr(component) + ((yPos >> componentScaleY) * srcStride) + (xPos >> componentScaleX); + + Int orgStride = orgYuv->getStride(component); + Pel* orgBlk = orgYuv->getAddr(component) + ((yPos >> componentScaleY) * orgStride) + (xPos >> componentScaleX); + + getBlkStats(component, blkStats[ctuRsAddr][component] + , srcBlk, orgBlk, srcStride, orgStride, (width >> componentScaleX), (height >> componentScaleY) + , isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , isCalculatePreDeblockSamples +#endif + ); + + } + } +} + +Void TEncSampleAdaptiveOffset::decidePicParams(Bool* sliceEnabled, Int picTempLayer) +{ + //decide sliceEnabled[compIdx] + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + for (Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + sliceEnabled[compIdx] = false; + } + + for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + // reset flags & counters + sliceEnabled[compIdx] = true; + +#if SAO_ENCODING_CHOICE +#if SAO_ENCODING_CHOICE_CHROMA + // decide slice-level on/off based on previous results + if( (picTempLayer > 0) + && (m_saoDisabledRate[compIdx][picTempLayer-1] > ((compIdx==COMPONENT_Y) ? SAO_ENCODING_RATE : SAO_ENCODING_RATE_CHROMA)) ) + { + sliceEnabled[compIdx] = false; + } +#else + // decide slice-level on/off based on previous results + if( (picTempLayer > 0) + && (m_saoDisabledRate[COMPONENT_Y][0] > SAO_ENCODING_RATE) ) + { + sliceEnabled[compIdx] = false; + } +#endif +#endif + } +} + +Int64 TEncSampleAdaptiveOffset::getDistortion(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* invQuantOffset, SAOStatData& statData) +{ + Int64 dist = 0; + Int shift = 2 * DISTORTION_PRECISION_ADJUSTMENT(g_bitDepth[toChannelType(compIdx)] - 8); + + switch(typeIdc) + { + case SAO_TYPE_EO_0: + case SAO_TYPE_EO_90: + case SAO_TYPE_EO_135: + case SAO_TYPE_EO_45: + { + for (Int offsetIdx=0; offsetIdx> shift); +} + + +inline Int TEncSampleAdaptiveOffset::estIterOffset(Int typeIdx, Int classIdx, Double lambda, Int offsetInput, Int64 count, Int64 diffSum, Int shift, Int bitIncrease, Int64& bestDist, Double& bestCost, Int offsetTh ) +{ + Int iterOffset, tempOffset; + Int64 tempDist, tempRate; + Double tempCost, tempMinCost; + Int offsetOutput = 0; + iterOffset = offsetInput; + // Assuming sending quantized value 0 results in zero offset and sending the value zero needs 1 bit. entropy coder can be used to measure the exact rate here. + tempMinCost = lambda; + while (iterOffset != 0) + { + // Calculate the bits required for signaling the offset + tempRate = (typeIdx == SAO_TYPE_BO) ? (abs((Int)iterOffset)+2) : (abs((Int)iterOffset)+1); + if (abs((Int)iterOffset)==offsetTh) //inclusive + { + tempRate --; + } + // Do the dequantization before distortion calculation + tempOffset = iterOffset << bitIncrease; + tempDist = estSaoDist( count, tempOffset, diffSum, shift); + tempCost = ((Double)tempDist + lambda * (Double) tempRate); + if(tempCost < tempMinCost) + { + tempMinCost = tempCost; + offsetOutput = iterOffset; + bestDist = tempDist; + bestCost = tempCost; + } + iterOffset = (iterOffset > 0) ? (iterOffset-1):(iterOffset+1); + } + return offsetOutput; +} + +Void TEncSampleAdaptiveOffset::deriveOffsets(ComponentID compIdx, Int typeIdc, SAOStatData& statData, Int* quantOffsets, Int& typeAuxInfo) +{ + Int bitDepth = g_bitDepth[toChannelType(compIdx)]; + Int shift = 2 * DISTORTION_PRECISION_ADJUSTMENT(bitDepth-8); + Int offsetTh = g_saoMaxOffsetQVal[compIdx]; //inclusive + + ::memset(quantOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES); + + //derive initial offsets + Int numClasses = (typeIdc == SAO_TYPE_BO)?((Int)NUM_SAO_BO_CLASSES):((Int)NUM_SAO_EO_CLASSES); + for(Int classIdx=0; classIdx< numClasses; classIdx++) + { + if( (typeIdc != SAO_TYPE_BO) && (classIdx==SAO_CLASS_EO_PLAIN) ) + { + continue; //offset will be zero + } + + if(statData.count[classIdx] == 0) + { + continue; //offset will be zero + } + + quantOffsets[classIdx] = (Int) xRoundIbdi(bitDepth, (Double)( statData.diff[classIdx]<<(bitDepth-8)) + / + (Double)( statData.count[classIdx]<< m_offsetStepLog2[compIdx]) + ); + quantOffsets[classIdx] = Clip3(-offsetTh, offsetTh, quantOffsets[classIdx]); + } + + // adjust offsets + switch(typeIdc) + { + case SAO_TYPE_EO_0: + case SAO_TYPE_EO_90: + case SAO_TYPE_EO_135: + case SAO_TYPE_EO_45: + { + Int64 classDist; + Double classCost; + for(Int classIdx=0; classIdx 0) quantOffsets[classIdx] =0; + if(classIdx==SAO_CLASS_EO_FULL_PEAK && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0; + + if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero + { + quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], classDist , classCost , offsetTh ); + } + } + + typeAuxInfo =0; + } + break; + case SAO_TYPE_BO: + { + Int64 distBOClasses[NUM_SAO_BO_CLASSES]; + Double costBOClasses[NUM_SAO_BO_CLASSES]; + ::memset(distBOClasses, 0, sizeof(Int64)*NUM_SAO_BO_CLASSES); + for(Int classIdx=0; classIdx< NUM_SAO_BO_CLASSES; classIdx++) + { + costBOClasses[classIdx]= m_lambda[compIdx]; + if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero + { + quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], distBOClasses[classIdx], costBOClasses[classIdx], offsetTh ); + } + } + + //decide the starting band index + Double minCost = MAX_DOUBLE, cost; + for(Int band=0; band< NUM_SAO_BO_CLASSES- 4+ 1; band++) + { + cost = costBOClasses[band ]; + cost += costBOClasses[band+1]; + cost += costBOClasses[band+2]; + cost += costBOClasses[band+3]; + + if(cost < minCost) + { + minCost = cost; + typeAuxInfo = band; + } + } + //clear those unused classes + Int clearQuantOffset[NUM_SAO_BO_CLASSES]; + ::memset(clearQuantOffset, 0, sizeof(Int)*NUM_SAO_BO_CLASSES); + for(Int i=0; i< 4; i++) + { + Int band = (typeAuxInfo+i)%NUM_SAO_BO_CLASSES; + clearQuantOffset[band] = quantOffsets[band]; + } + ::memcpy(quantOffsets, clearQuantOffset, sizeof(Int)*NUM_SAO_BO_CLASSES); + } + break; + default: + { + printf("Not a supported type"); + assert(0); + exit(-1); + } + + } + + +} + +Void TEncSampleAdaptiveOffset::deriveModeNewRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel) +{ + Double minCost, cost; + UInt previousWrittenBits; + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + + Int64 dist[MAX_NUM_COMPONENT], modeDist[MAX_NUM_COMPONENT]; + SAOOffset testOffset[MAX_NUM_COMPONENT]; + Int invQuantOffset[MAX_NUM_SAO_CLASSES]; + for(Int comp=0; comp < MAX_NUM_COMPONENT; comp++) + { + modeDist[comp] = 0; + } + + //pre-encode merge flags + modeParam[COMPONENT_Y].modeIdc = SAO_MODE_OFF; + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); + m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), true); + m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); + + //------ luma --------// + { + ComponentID compIdx = COMPONENT_Y; + //"off" case as initial cost + modeParam[compIdx].modeIdc = SAO_MODE_OFF; + m_pcRDGoOnSbacCoder->resetBits(); + m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, modeParam[compIdx], sliceEnabled[compIdx]); + modeDist[compIdx] = 0; + minCost= m_lambda[compIdx]*((Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits()); + m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); + if(sliceEnabled[compIdx]) + { + for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++) + { + testOffset[compIdx].modeIdc = SAO_MODE_NEW; + testOffset[compIdx].typeIdc = typeIdc; + + //derive coded offset + deriveOffsets(compIdx, typeIdc, blkStats[ctuRsAddr][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo); + + //inversed quantized offsets + invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset); + + //get distortion + dist[compIdx] = getDistortion(compIdx, testOffset[compIdx].typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctuRsAddr][compIdx][typeIdc]); + + //get rate + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); + m_pcRDGoOnSbacCoder->resetBits(); + m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]); + Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); + cost = (Double)dist[compIdx] + m_lambda[compIdx]*((Double)rate); + if(cost < minCost) + { + minCost = cost; + modeDist[compIdx] = dist[compIdx]; + modeParam[compIdx]= testOffset[compIdx]; + m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); + } + } + } + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); + m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); + } + + //------ chroma --------// +//"off" case as initial cost + cost = 0; + previousWrittenBits = 0; + m_pcRDGoOnSbacCoder->resetBits(); + for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++) + { + const ComponentID component = ComponentID(componentIndex); + + modeParam[component].modeIdc = SAO_MODE_OFF; + modeDist [component] = 0; + m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, modeParam[component], sliceEnabled[component]); + + const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); + cost += m_lambda[component] * (currentWrittenBits - previousWrittenBits); + previousWrittenBits = currentWrittenBits; + } + + minCost = cost; + + //doesn't need to store cabac status here since the whole CTU parameters will be re-encoded at the end of this function + + for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++) + { + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]); + m_pcRDGoOnSbacCoder->resetBits(); + previousWrittenBits = 0; + cost = 0; + + for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++) + { + const ComponentID component = ComponentID(componentIndex); + if(!sliceEnabled[component]) + { + testOffset[component].modeIdc = SAO_MODE_OFF; + dist[component]= 0; + continue; + } + testOffset[component].modeIdc = SAO_MODE_NEW; + testOffset[component].typeIdc = typeIdc; + + //derive offset & get distortion + deriveOffsets(component, typeIdc, blkStats[ctuRsAddr][component][typeIdc], testOffset[component].offset, testOffset[component].typeAuxInfo); + invertQuantOffsets(component, typeIdc, testOffset[component].typeAuxInfo, invQuantOffset, testOffset[component].offset); + dist[component] = getDistortion(component, typeIdc, testOffset[component].typeAuxInfo, invQuantOffset, blkStats[ctuRsAddr][component][typeIdc]); + + m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, testOffset[component], sliceEnabled[component]); + + const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); + cost += dist[component] + (m_lambda[component] * (currentWrittenBits - previousWrittenBits)); + previousWrittenBits = currentWrittenBits; + } + + if(cost < minCost) + { + minCost = cost; + for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++) + { + modeDist[componentIndex] = dist[componentIndex]; + modeParam[componentIndex] = testOffset[componentIndex]; + } + } + + } // SAO_TYPE loop + + //----- re-gen rate & normalized cost----// + modeNormCost = 0; + for(UInt componentIndex = COMPONENT_Y; componentIndex < numberOfComponents; componentIndex++) + { + modeNormCost += (Double)modeDist[componentIndex] / m_lambda[componentIndex]; + } + + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); + m_pcRDGoOnSbacCoder->resetBits(); + m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false); + modeNormCost += (Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); +} + +Void TEncSampleAdaptiveOffset::deriveModeMergeRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel) +{ + modeNormCost = MAX_DOUBLE; + + Double cost; + SAOBlkParam testBlkParam; + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + + for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++) + { + if(mergeList[mergeType] == NULL) + { + continue; + } + + testBlkParam = *(mergeList[mergeType]); + //normalized distortion + Double normDist=0; + for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + testBlkParam[compIdx].modeIdc = SAO_MODE_MERGE; + testBlkParam[compIdx].typeIdc = mergeType; + + SAOOffset& mergedOffsetParam = (*(mergeList[mergeType]))[compIdx]; + + if( mergedOffsetParam.modeIdc != SAO_MODE_OFF) + { + //offsets have been reconstructed. Don't call inversed quantization function. + normDist += (((Double)getDistortion(ComponentID(compIdx), mergedOffsetParam.typeIdc, mergedOffsetParam.typeAuxInfo, mergedOffsetParam.offset, blkStats[ctuRsAddr][compIdx][mergedOffsetParam.typeIdc])) + /m_lambda[compIdx] + ); + } + + } + + //rate + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]); + m_pcRDGoOnSbacCoder->resetBits(); + m_pcRDGoOnSbacCoder->codeSAOBlkParam(testBlkParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false); + Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits(); + + cost = normDist+(Double)rate; + + if(cost < modeNormCost) + { + modeNormCost = cost; + modeParam = testBlkParam; + m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); + } + } + + m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]); +} + +Void TEncSampleAdaptiveOffset::decideBlkParams(TComPic* pic, Bool* sliceEnabled, SAOStatData*** blkStats, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam* reconParams, SAOBlkParam* codedParams) +{ + Bool allBlksDisabled = true; + const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC); + for(Int compId = COMPONENT_Y; compId < numberOfComponents; compId++) + { + if (sliceEnabled[compId]) + allBlksDisabled = false; + } + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]); + + SAOBlkParam modeParam; + Double minCost, modeCost; + + +#if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL + Double totalCost = 0; +#endif + + for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++) + { + if(allBlksDisabled) + { + codedParams[ctuRsAddr].reset(); + continue; + } + + m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_CUR ]); + + //get merge list + SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL }; + getMergeList(pic, ctuRsAddr, reconParams, mergeList); + + minCost = MAX_DOUBLE; + for(Int mode=0; mode < NUM_SAO_MODES; mode++) + { + switch(mode) + { + case SAO_MODE_OFF: + { + continue; //not necessary, since all-off case will be tested in SAO_MODE_NEW case. + } + break; + case SAO_MODE_NEW: + { + deriveModeNewRDO(ctuRsAddr, mergeList, sliceEnabled, blkStats, modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR); + + } + break; + case SAO_MODE_MERGE: + { + deriveModeMergeRDO(ctuRsAddr, mergeList, sliceEnabled, blkStats , modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR); + } + break; + default: + { + printf("Not a supported SAO mode\n"); + assert(0); + exit(-1); + } + } + + if(modeCost < minCost) + { + minCost = modeCost; + codedParams[ctuRsAddr] = modeParam; + m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]); + } + } //mode + +#if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL + totalCost += minCost; +#endif + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]); + + //apply reconstructed offsets + reconParams[ctuRsAddr] = codedParams[ctuRsAddr]; + reconstructBlkSAOParam(reconParams[ctuRsAddr], mergeList); + offsetCTU(ctuRsAddr, srcYuv, resYuv, reconParams[ctuRsAddr], pic); + } //ctuRsAddr + +#if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL + if (!allBlksDisabled && (totalCost >= 0)) //SAO is not beneficial - disable it + { + for(Int ctuRsAddr = 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++) + { + codedParams[ctuRsAddr].reset(); + } + + for (UInt componentIndex = 0; componentIndex < MAX_NUM_COMPONENT; componentIndex++) + { + sliceEnabled[componentIndex] = false; + } + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]); + } +#endif + +#if SAO_ENCODING_CHOICE + Int picTempLayer = pic->getSlice(0)->getDepth(); + Int numCtusForSAOOff[MAX_NUM_COMPONENT]; + + for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + numCtusForSAOOff[compIdx] = 0; + for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++) + { + if( reconParams[ctuRsAddr][compIdx].modeIdc == SAO_MODE_OFF) + { + numCtusForSAOOff[compIdx]++; + } + } + } +#if SAO_ENCODING_CHOICE_CHROMA + for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++) + { + m_saoDisabledRate[compIdx][picTempLayer] = (Double)numCtusForSAOOff[compIdx]/(Double)m_numCTUsPic; + } +#else + if (picTempLayer == 0) + { + m_saoDisabledRate[COMPONENT_Y][0] = (Double)(numCtusForSAOOff[COMPONENT_Y]+numCtusForSAOOff[COMPONENT_Cb]+numCtusForSAOOff[COMPONENT_Cr])/(Double)(m_numCTUsPic*3); + } +#endif +#endif +} + + +Void TEncSampleAdaptiveOffset::getBlkStats(ComponentID compIdx, SAOStatData* statsDataTypes + , Pel* srcBlk, Pel* orgBlk, Int srcStride, Int orgStride, Int width, Int height + , Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isCalculatePreDeblockSamples +#endif + ) +{ + if(m_lineBufWidth != m_maxCUWidth) + { + m_lineBufWidth = m_maxCUWidth; + + if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL; + m_signLineBuf1 = new Char[m_lineBufWidth+1]; + + if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL; + m_signLineBuf2 = new Char[m_lineBufWidth+1]; + } + + Int x,y, startX, startY, endX, endY, edgeType, firstLineStartX, firstLineEndX; + Char signLeft, signRight, signDown; + Int64 *diff, *count; + Pel *srcLine, *orgLine; + Int* skipLinesR = m_skipLinesR[compIdx]; + Int* skipLinesB = m_skipLinesB[compIdx]; + + for(Int typeIdx=0; typeIdx< NUM_SAO_NEW_TYPES; typeIdx++) + { + SAOStatData& statsData= statsDataTypes[typeIdx]; + statsData.reset(); + + srcLine = srcBlk; + orgLine = orgBlk; + diff = statsData.diff; + count = statsData.count; + switch(typeIdx) + { + case SAO_TYPE_EO_0: + { + diff +=2; + count+=2; + endY = (isBelowAvail) ? (height - skipLinesB[typeIdx]) : height; +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail ? 0 : 1) + : (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1)) + ; +#else + startX = isLeftAvail ? 0 : 1; +#endif +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + endX = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1)) + : (isRightAvail ? width : (width - 1)) + ; +#else + endX = isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1); +#endif + for (y=0; y> shiftBits; + diff [bandIdx] += (orgLine[x] - srcLine[x]); + count[bandIdx] ++; + } + srcLine += srcStride; + orgLine += orgStride; + } +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + if(isCalculatePreDeblockSamples) + { + if(isBelowAvail) + { + startX = 0; + endX = width; + + for(y= 0; y< skipLinesB[typeIdx]; y++) + { + for (x=startX; x< endX; x++) + { + Int bandIdx= srcLine[x] >> shiftBits; + diff [bandIdx] += (orgLine[x] - srcLine[x]); + count[bandIdx] ++; + } + srcLine += srcStride; + orgLine += orgStride; + + } + + } + } +#endif + } + break; + default: + { + printf("Not a supported SAO types\n"); + assert(0); + exit(-1); + } + } + } +} + + +//! \} diff --git a/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.h b/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.h new file mode 100644 index 0000000..f3061d7 --- /dev/null +++ b/jctvc/TLibEncoder/TEncSampleAdaptiveOffset.h @@ -0,0 +1,168 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + \file TEncSampleAdaptiveOffset.h + \brief estimation part of sample adaptive offset class (header) + */ + +#ifndef __TENCSAMPLEADAPTIVEOFFSET__ +#define __TENCSAMPLEADAPTIVEOFFSET__ + +#include "TLibCommon/TComSampleAdaptiveOffset.h" +#include "TLibCommon/TComPic.h" + +#include "TEncEntropy.h" +#include "TEncSbac.h" +#include "TLibCommon/TComBitCounter.h" + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +enum SAOCabacStateLablesRDO //CABAC state labels +{ + SAO_CABACSTATE_PIC_INIT =0, + SAO_CABACSTATE_BLK_CUR, + SAO_CABACSTATE_BLK_NEXT, + SAO_CABACSTATE_BLK_MID, + SAO_CABACSTATE_BLK_TEMP, + NUM_SAO_CABACSTATE_LABELS +}; + +struct SAOStatData //data structure for SAO statistics +{ + Int64 diff[MAX_NUM_SAO_CLASSES]; + Int64 count[MAX_NUM_SAO_CLASSES]; + + SAOStatData(){} + ~SAOStatData(){} + Void reset() + { + ::memset(diff, 0, sizeof(Int64)*MAX_NUM_SAO_CLASSES); + ::memset(count, 0, sizeof(Int64)*MAX_NUM_SAO_CLASSES); + } + const SAOStatData& operator=(const SAOStatData& src) + { + ::memcpy(diff, src.diff, sizeof(Int64)*MAX_NUM_SAO_CLASSES); + ::memcpy(count, src.count, sizeof(Int64)*MAX_NUM_SAO_CLASSES); + return *this; + } +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + const SAOStatData& operator+= (const SAOStatData& src) + { + for(Int i=0; i< MAX_NUM_SAO_CLASSES; i++) + { + diff[i] += src.diff[i]; + count[i] += src.count[i]; + } + return *this; + } +#endif +}; + +class TEncSampleAdaptiveOffset : public TComSampleAdaptiveOffset +{ +public: + TEncSampleAdaptiveOffset(); + virtual ~TEncSampleAdaptiveOffset(); + + //interface +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + Void createEncData(Bool isPreDBFSamplesUsed); +#else + Void createEncData(); +#endif + Void destroyEncData(); + Void initRDOCabacCoder(TEncSbac* pcRDGoOnSbacCoder, TComSlice* pcSlice) ; + Void SAOProcess(TComPic* pPic, Bool* sliceEnabled, const Double *lambdas +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isPreDBFSamplesUsed +#endif + ); +public: //methods +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + Void getPreDBFStatistics(TComPic* pPic); +#endif +private: //methods + Void getStatistics(SAOStatData*** blkStats, TComPicYuv* orgYuv, TComPicYuv* srcYuv,TComPic* pPic +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isCalculatePreDeblockSamples = false +#endif + ); + Void decidePicParams(Bool* sliceEnabled, Int picTempLayer); + Void decideBlkParams(TComPic* pic, Bool* sliceEnabled, SAOStatData*** blkStats, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam* reconParams, SAOBlkParam* codedParams); + Void getBlkStats(ComponentID compIdx, SAOStatData* statsDataTypes, Pel* srcBlk, Pel* orgBlk, Int srcStride, Int orgStride, Int width, Int height, Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + , Bool isCalculatePreDeblockSamples +#endif + ); + Void deriveModeNewRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel); + Void deriveModeMergeRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel); + Int64 getDistortion(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* offsetVal, SAOStatData& statData); + Void deriveOffsets(ComponentID compIdx, Int typeIdc, SAOStatData& statData, Int* quantOffsets, Int& typeAuxInfo); + inline Int64 estSaoDist(Int64 count, Int64 offset, Int64 diffSum, Int shift); + inline Int estIterOffset(Int typeIdx, Int classIdx, Double lambda, Int offsetInput, Int64 count, Int64 diffSum, Int shift, Int bitIncrease, Int64& bestDist, Double& bestCost, Int offsetTh ); +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + Void addPreDBFStatistics(SAOStatData*** blkStats); +#endif +private: //members + //for RDO + TEncSbac** m_pppcRDSbacCoder; + TEncSbac* m_pcRDGoOnSbacCoder; +#if FAST_BIT_EST + TEncBinCABACCounter** m_pppcBinCoderCABAC; +#else + TEncBinCABAC** m_pppcBinCoderCABAC; +#endif + Double m_lambda[MAX_NUM_COMPONENT]; + + //statistics + SAOStatData*** m_statData; //[ctu][comp][classes] +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + SAOStatData*** m_preDBFstatData; +#endif +#if SAO_ENCODING_CHOICE + Double m_saoDisabledRate[MAX_NUM_COMPONENT][MAX_TLAYER]; +#endif + Int m_skipLinesR[MAX_NUM_COMPONENT][NUM_SAO_NEW_TYPES]; + Int m_skipLinesB[MAX_NUM_COMPONENT][NUM_SAO_NEW_TYPES]; +}; + + +//! \} + +#endif diff --git a/jctvc/TLibEncoder/TEncSbac.cpp b/jctvc/TLibEncoder/TEncSbac.cpp new file mode 100644 index 0000000..f0c5843 --- /dev/null +++ b/jctvc/TLibEncoder/TEncSbac.cpp @@ -0,0 +1,2008 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncSbac.cpp + \brief SBAC encoder class +*/ + +#include "TEncTop.h" +#include "TEncSbac.h" +#include "TLibCommon/TComTU.h" + +#include +#include + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST +#include "../TLibCommon/Debug.h" +#endif + + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TEncSbac::TEncSbac() +// new structure here +: m_pcBitIf ( NULL ) +, m_pcSlice ( NULL ) +, m_pcBinIf ( NULL ) +, m_numContextModels ( 0 ) +, m_cCUSplitFlagSCModel ( 1, 1, NUM_SPLIT_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUSkipFlagSCModel ( 1, 1, NUM_SKIP_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUMergeFlagExtSCModel ( 1, 1, NUM_MERGE_FLAG_EXT_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUMergeIdxExtSCModel ( 1, 1, NUM_MERGE_IDX_EXT_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUPartSizeSCModel ( 1, 1, NUM_PART_SIZE_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUPredModeSCModel ( 1, 1, NUM_PRED_MODE_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUIntraPredSCModel ( 1, 1, NUM_ADI_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUChromaPredSCModel ( 1, 1, NUM_CHROMA_PRED_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUDeltaQpSCModel ( 1, 1, NUM_DELTA_QP_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUInterDirSCModel ( 1, 1, NUM_INTER_DIR_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCURefPicSCModel ( 1, 1, NUM_REF_NO_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUMvdSCModel ( 1, 1, NUM_MV_RES_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUQtCbfSCModel ( 1, NUM_QT_CBF_CTX_SETS, NUM_QT_CBF_CTX_PER_SET , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUTransSubdivFlagSCModel ( 1, 1, NUM_TRANS_SUBDIV_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUQtRootCbfSCModel ( 1, 1, NUM_QT_ROOT_CBF_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUSigCoeffGroupSCModel ( 1, 2, NUM_SIG_CG_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUSigSCModel ( 1, 1, NUM_SIG_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCuCtxLastX ( 1, NUM_CTX_LAST_FLAG_SETS, NUM_CTX_LAST_FLAG_XY , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCuCtxLastY ( 1, NUM_CTX_LAST_FLAG_SETS, NUM_CTX_LAST_FLAG_XY , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUOneSCModel ( 1, 1, NUM_ONE_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCUAbsSCModel ( 1, 1, NUM_ABS_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cMVPIdxSCModel ( 1, 1, NUM_MVP_IDX_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cSaoMergeSCModel ( 1, 1, NUM_SAO_MERGE_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cSaoTypeIdxSCModel ( 1, 1, NUM_SAO_TYPE_IDX_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cTransformSkipSCModel ( 1, MAX_NUM_CHANNEL_TYPE, NUM_TRANSFORMSKIP_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_CUTransquantBypassFlagSCModel ( 1, 1, NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_explicitRdpcmFlagSCModel ( 1, MAX_NUM_CHANNEL_TYPE, NUM_EXPLICIT_RDPCM_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_explicitRdpcmDirSCModel ( 1, MAX_NUM_CHANNEL_TYPE, NUM_EXPLICIT_RDPCM_DIR_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_cCrossComponentPredictionSCModel ( 1, 1, NUM_CROSS_COMPONENT_PREDICTION_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_ChromaQpAdjFlagSCModel ( 1, 1, NUM_CHROMA_QP_ADJ_FLAG_CTX , m_contextModels + m_numContextModels, m_numContextModels) +, m_ChromaQpAdjIdcSCModel ( 1, 1, NUM_CHROMA_QP_ADJ_IDC_CTX , m_contextModels + m_numContextModels, m_numContextModels) +{ + assert( m_numContextModels <= MAX_NUM_CTX_MOD ); +} + +TEncSbac::~TEncSbac() +{ +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +Void TEncSbac::resetEntropy () +{ + Int iQp = m_pcSlice->getSliceQp(); + SliceType eSliceType = m_pcSlice->getSliceType(); + + Int encCABACTableIdx = m_pcSlice->getPPS()->getEncCABACTableIdx(); + if (!m_pcSlice->isIntra() && (encCABACTableIdx==B_SLICE || encCABACTableIdx==P_SLICE) && m_pcSlice->getPPS()->getCabacInitPresentFlag()) + { + eSliceType = (SliceType) encCABACTableIdx; + } + + m_cCUSplitFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SPLIT_FLAG ); + m_cCUSkipFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SKIP_FLAG ); + m_cCUMergeFlagExtSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_MERGE_FLAG_EXT); + m_cCUMergeIdxExtSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_MERGE_IDX_EXT); + m_cCUPartSizeSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_PART_SIZE ); + m_cCUPredModeSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_PRED_MODE ); + m_cCUIntraPredSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_INTRA_PRED_MODE ); + m_cCUChromaPredSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_CHROMA_PRED_MODE ); + m_cCUInterDirSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_INTER_DIR ); + m_cCUMvdSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_MVD ); + m_cCURefPicSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_REF_PIC ); + m_cCUDeltaQpSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_DQP ); + m_cCUQtCbfSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_QT_CBF ); + m_cCUQtRootCbfSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_QT_ROOT_CBF ); + m_cCUSigCoeffGroupSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SIG_CG_FLAG ); + m_cCUSigSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SIG_FLAG ); + m_cCuCtxLastX.initBuffer ( eSliceType, iQp, (UChar*)INIT_LAST ); + m_cCuCtxLastY.initBuffer ( eSliceType, iQp, (UChar*)INIT_LAST ); + m_cCUOneSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_ONE_FLAG ); + m_cCUAbsSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_ABS_FLAG ); + m_cMVPIdxSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_MVP_IDX ); + m_cCUTransSubdivFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_TRANS_SUBDIV_FLAG ); + m_cSaoMergeSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SAO_MERGE_FLAG ); + m_cSaoTypeIdxSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SAO_TYPE_IDX ); + m_cTransformSkipSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_TRANSFORMSKIP_FLAG ); + m_CUTransquantBypassFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_CU_TRANSQUANT_BYPASS_FLAG ); + m_explicitRdpcmFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_EXPLICIT_RDPCM_FLAG); + m_explicitRdpcmDirSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_EXPLICIT_RDPCM_DIR); + m_cCrossComponentPredictionSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_CROSS_COMPONENT_PREDICTION ); + m_ChromaQpAdjFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_CHROMA_QP_ADJ_FLAG ); + m_ChromaQpAdjIdcSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_CHROMA_QP_ADJ_IDC ); + + for (UInt statisticIndex = 0; statisticIndex < RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS ; statisticIndex++) + { + m_golombRiceAdaptationStatistics[statisticIndex] = 0; + } + + m_pcBinIf->start(); + + return; +} + +/** The function does the following: + * If current slice type is P/B then it determines the distance of initialisation type 1 and 2 from the current CABAC states and + * stores the index of the closest table. This index is used for the next P/B slice when cabac_init_present_flag is true. + */ +Void TEncSbac::determineCabacInitIdx() +{ + Int qp = m_pcSlice->getSliceQp(); + + if (!m_pcSlice->isIntra()) + { + SliceType aSliceTypeChoices[] = {B_SLICE, P_SLICE}; + + UInt bestCost = MAX_UINT; + SliceType bestSliceType = aSliceTypeChoices[0]; + for (UInt idx=0; idx<2; idx++) + { + UInt curCost = 0; + SliceType curSliceType = aSliceTypeChoices[idx]; + + curCost = m_cCUSplitFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SPLIT_FLAG ); + curCost += m_cCUSkipFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SKIP_FLAG ); + curCost += m_cCUMergeFlagExtSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_MERGE_FLAG_EXT); + curCost += m_cCUMergeIdxExtSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_MERGE_IDX_EXT); + curCost += m_cCUPartSizeSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_PART_SIZE ); + curCost += m_cCUPredModeSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_PRED_MODE ); + curCost += m_cCUIntraPredSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_INTRA_PRED_MODE ); + curCost += m_cCUChromaPredSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_CHROMA_PRED_MODE ); + curCost += m_cCUInterDirSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_INTER_DIR ); + curCost += m_cCUMvdSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_MVD ); + curCost += m_cCURefPicSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_REF_PIC ); + curCost += m_cCUDeltaQpSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_DQP ); + curCost += m_cCUQtCbfSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_QT_CBF ); + curCost += m_cCUQtRootCbfSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_QT_ROOT_CBF ); + curCost += m_cCUSigCoeffGroupSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SIG_CG_FLAG ); + curCost += m_cCUSigSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SIG_FLAG ); + curCost += m_cCuCtxLastX.calcCost ( curSliceType, qp, (UChar*)INIT_LAST ); + curCost += m_cCuCtxLastY.calcCost ( curSliceType, qp, (UChar*)INIT_LAST ); + curCost += m_cCUOneSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_ONE_FLAG ); + curCost += m_cCUAbsSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_ABS_FLAG ); + curCost += m_cMVPIdxSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_MVP_IDX ); + curCost += m_cCUTransSubdivFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_TRANS_SUBDIV_FLAG ); + curCost += m_cSaoMergeSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SAO_MERGE_FLAG ); + curCost += m_cSaoTypeIdxSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_SAO_TYPE_IDX ); + curCost += m_cTransformSkipSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_TRANSFORMSKIP_FLAG ); + curCost += m_CUTransquantBypassFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_CU_TRANSQUANT_BYPASS_FLAG ); + curCost += m_explicitRdpcmFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_EXPLICIT_RDPCM_FLAG); + curCost += m_explicitRdpcmDirSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_EXPLICIT_RDPCM_DIR); + curCost += m_cCrossComponentPredictionSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_CROSS_COMPONENT_PREDICTION ); + curCost += m_ChromaQpAdjFlagSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_CHROMA_QP_ADJ_FLAG ); + curCost += m_ChromaQpAdjIdcSCModel.calcCost ( curSliceType, qp, (UChar*)INIT_CHROMA_QP_ADJ_IDC ); + + if (curCost < bestCost) + { + bestSliceType = curSliceType; + bestCost = curCost; + } + } + m_pcSlice->getPPS()->setEncCABACTableIdx( bestSliceType ); + } + else + { + m_pcSlice->getPPS()->setEncCABACTableIdx( I_SLICE ); + } +} + +Void TEncSbac::codeVPS( TComVPS* pcVPS ) +{ + assert (0); + return; +} + +Void TEncSbac::codeSPS( TComSPS* pcSPS ) +{ + assert (0); + return; +} + +Void TEncSbac::codePPS( TComPPS* pcPPS ) +{ + assert (0); + return; +} + +Void TEncSbac::codeSliceHeader( TComSlice* pcSlice ) +{ + assert (0); + return; +} + +Void TEncSbac::codeTilesWPPEntryPoint( TComSlice* pSlice ) +{ + assert (0); + return; +} + +Void TEncSbac::codeTerminatingBit( UInt uilsLast ) +{ + m_pcBinIf->encodeBinTrm( uilsLast ); +} + +Void TEncSbac::codeSliceFinish() +{ + m_pcBinIf->finish(); +} + +Void TEncSbac::xWriteUnarySymbol( UInt uiSymbol, ContextModel* pcSCModel, Int iOffset ) +{ + m_pcBinIf->encodeBin( uiSymbol ? 1 : 0, pcSCModel[0] ); + + if( 0 == uiSymbol) + { + return; + } + + while( uiSymbol-- ) + { + m_pcBinIf->encodeBin( uiSymbol ? 1 : 0, pcSCModel[ iOffset ] ); + } + + return; +} + +Void TEncSbac::xWriteUnaryMaxSymbol( UInt uiSymbol, ContextModel* pcSCModel, Int iOffset, UInt uiMaxSymbol ) +{ + if (uiMaxSymbol == 0) + { + return; + } + + m_pcBinIf->encodeBin( uiSymbol ? 1 : 0, pcSCModel[ 0 ] ); + + if ( uiSymbol == 0 ) + { + return; + } + + Bool bCodeLast = ( uiMaxSymbol > uiSymbol ); + + while( --uiSymbol ) + { + m_pcBinIf->encodeBin( 1, pcSCModel[ iOffset ] ); + } + if( bCodeLast ) + { + m_pcBinIf->encodeBin( 0, pcSCModel[ iOffset ] ); + } + + return; +} + +Void TEncSbac::xWriteEpExGolomb( UInt uiSymbol, UInt uiCount ) +{ + UInt bins = 0; + Int numBins = 0; + + while( uiSymbol >= (UInt)(1<encodeBinsEP( bins, numBins ); +} + + +/** Coding of coeff_abs_level_minus3 + * \param uiSymbol value of coeff_abs_level_minus3 + * \param ruiGoRiceParam reference to Rice parameter + * \returns Void + */ +Void TEncSbac::xWriteCoefRemainExGolomb ( UInt symbol, UInt &rParam, const Bool useLimitedPrefixLength, const ChannelType channelType ) +{ + Int codeNumber = (Int)symbol; + UInt length; + + if (codeNumber < (COEF_REMAIN_BIN_REDUCTION << rParam)) + { + length = codeNumber>>rParam; + m_pcBinIf->encodeBinsEP( (1<<(length+1))-2 , length+1); + m_pcBinIf->encodeBinsEP((codeNumber%(1<> rParam) - COEF_REMAIN_BIN_REDUCTION; + + if (codeValue >= ((1 << maximumPrefixLength) - 1)) + { + prefixLength = maximumPrefixLength; + suffixLength = g_maxTrDynamicRange[channelType] - rParam; + } + else + { + while (codeValue > ((2 << prefixLength) - 2)) + { + prefixLength++; + } + + suffixLength = prefixLength + 1; //+1 for the separator bit + } + + const UInt suffix = codeValue - ((1 << prefixLength) - 1); + + const UInt totalPrefixLength = prefixLength + COEF_REMAIN_BIN_REDUCTION; + const UInt prefix = (1 << totalPrefixLength) - 1; + const UInt rParamBitMask = (1 << rParam) - 1; + + m_pcBinIf->encodeBinsEP( prefix, totalPrefixLength ); //prefix + m_pcBinIf->encodeBinsEP(((suffix << rParam) | (symbol & rParamBitMask)), (suffixLength + rParam)); //separator, suffix, and rParam bits + } + else + { + length = rParam; + codeNumber = codeNumber - ( COEF_REMAIN_BIN_REDUCTION << rParam); + + while (codeNumber >= (1<encodeBinsEP((1<<(COEF_REMAIN_BIN_REDUCTION+length+1-rParam))-2,COEF_REMAIN_BIN_REDUCTION+length+1-rParam); + m_pcBinIf->encodeBinsEP(codeNumber,length); + } +} + +// SBAC RD +Void TEncSbac::load ( const TEncSbac* pSrc) +{ + this->xCopyFrom(pSrc); +} + +Void TEncSbac::loadIntraDirMode( const TEncSbac* pSrc, const ChannelType chType ) +{ + m_pcBinIf->copyState( pSrc->m_pcBinIf ); + if (isLuma(chType)) + this->m_cCUIntraPredSCModel .copyFrom( &pSrc->m_cCUIntraPredSCModel ); + else + this->m_cCUChromaPredSCModel .copyFrom( &pSrc->m_cCUChromaPredSCModel ); +} + + +Void TEncSbac::store( TEncSbac* pDest) const +{ + pDest->xCopyFrom( this ); +} + + +Void TEncSbac::xCopyFrom( const TEncSbac* pSrc ) +{ + m_pcBinIf->copyState( pSrc->m_pcBinIf ); + xCopyContextsFrom(pSrc); +} + +Void TEncSbac::codeMVPIdx ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + Int iSymbol = pcCU->getMVPIdx(eRefList, uiAbsPartIdx); + Int iNum = AMVP_MAX_NUM_CANDS; + + xWriteUnaryMaxSymbol(iSymbol, m_cMVPIdxSCModel.get(0), 1, iNum-1); +} + +Void TEncSbac::codePartSize( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + PartSize eSize = pcCU->getPartitionSize( uiAbsPartIdx ); + + if ( pcCU->isIntra( uiAbsPartIdx ) ) + { + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth ) + { + m_pcBinIf->encodeBin( eSize == SIZE_2Nx2N? 1 : 0, m_cCUPartSizeSCModel.get( 0, 0, 0 ) ); + } + return; + } + + switch(eSize) + { + case SIZE_2Nx2N: + { + m_pcBinIf->encodeBin( 1, m_cCUPartSizeSCModel.get( 0, 0, 0) ); + break; + } + case SIZE_2NxN: + case SIZE_2NxnU: + case SIZE_2NxnD: + { + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 0) ); + m_pcBinIf->encodeBin( 1, m_cCUPartSizeSCModel.get( 0, 0, 1) ); + if ( pcCU->getSlice()->getSPS()->getAMPAcc( uiDepth ) ) + { + if (eSize == SIZE_2NxN) + { + m_pcBinIf->encodeBin(1, m_cCUPartSizeSCModel.get( 0, 0, 3 )); + } + else + { + m_pcBinIf->encodeBin(0, m_cCUPartSizeSCModel.get( 0, 0, 3 )); + m_pcBinIf->encodeBinEP((eSize == SIZE_2NxnU? 0: 1)); + } + } + break; + } + case SIZE_Nx2N: + case SIZE_nLx2N: + case SIZE_nRx2N: + { + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 0) ); + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 1) ); + + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth && !( pcCU->getWidth(uiAbsPartIdx) == 8 && pcCU->getHeight(uiAbsPartIdx) == 8 ) ) + { + m_pcBinIf->encodeBin( 1, m_cCUPartSizeSCModel.get( 0, 0, 2) ); + } + + if ( pcCU->getSlice()->getSPS()->getAMPAcc( uiDepth ) ) + { + if (eSize == SIZE_Nx2N) + { + m_pcBinIf->encodeBin(1, m_cCUPartSizeSCModel.get( 0, 0, 3 )); + } + else + { + m_pcBinIf->encodeBin(0, m_cCUPartSizeSCModel.get( 0, 0, 3 )); + m_pcBinIf->encodeBinEP((eSize == SIZE_nLx2N? 0: 1)); + } + } + break; + } + case SIZE_NxN: + { + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth && !( pcCU->getWidth(uiAbsPartIdx) == 8 && pcCU->getHeight(uiAbsPartIdx) == 8 ) ) + { + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 0) ); + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 1) ); + m_pcBinIf->encodeBin( 0, m_cCUPartSizeSCModel.get( 0, 0, 2) ); + } + break; + } + default: + { + assert(0); + break; + } + } +} + + +/** code prediction mode + * \param pcCU + * \param uiAbsPartIdx + * \returns Void + */ +Void TEncSbac::codePredMode( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + // get context function is here + m_pcBinIf->encodeBin( pcCU->isIntra( uiAbsPartIdx ) ? 1 : 0, m_cCUPredModeSCModel.get( 0, 0, 0 ) ); +} + +Void TEncSbac::codeCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + UInt uiSymbol = pcCU->getCUTransquantBypass(uiAbsPartIdx); + m_pcBinIf->encodeBin( uiSymbol, m_CUTransquantBypassFlagSCModel.get( 0, 0, 0 ) ); +} + +/** code skip flag + * \param pcCU + * \param uiAbsPartIdx + * \returns Void + */ +Void TEncSbac::codeSkipFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + // get context function is here + UInt uiSymbol = pcCU->isSkipped( uiAbsPartIdx ) ? 1 : 0; + UInt uiCtxSkip = pcCU->getCtxSkipFlag( uiAbsPartIdx ) ; + m_pcBinIf->encodeBin( uiSymbol, m_cCUSkipFlagSCModel.get( 0, 0, uiCtxSkip ) ); + DTRACE_CABAC_VL( g_nSymbolCounter++ ); + DTRACE_CABAC_T( "\tSkipFlag" ); + DTRACE_CABAC_T( "\tuiCtxSkip: "); + DTRACE_CABAC_V( uiCtxSkip ); + DTRACE_CABAC_T( "\tuiSymbol: "); + DTRACE_CABAC_V( uiSymbol ); + DTRACE_CABAC_T( "\n"); +} + +/** code merge flag + * \param pcCU + * \param uiAbsPartIdx + * \returns Void + */ +Void TEncSbac::codeMergeFlag( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + const UInt uiSymbol = pcCU->getMergeFlag( uiAbsPartIdx ) ? 1 : 0; + m_pcBinIf->encodeBin( uiSymbol, *m_cCUMergeFlagExtSCModel.get( 0 ) ); + + DTRACE_CABAC_VL( g_nSymbolCounter++ ); + DTRACE_CABAC_T( "\tMergeFlag: " ); + DTRACE_CABAC_V( uiSymbol ); + DTRACE_CABAC_T( "\tAddress: " ); + DTRACE_CABAC_V( pcCU->getCtuRsAddr() ); + DTRACE_CABAC_T( "\tuiAbsPartIdx: " ); + DTRACE_CABAC_V( uiAbsPartIdx ); + DTRACE_CABAC_T( "\n" ); +} + +/** code merge index + * \param pcCU + * \param uiAbsPartIdx + * \returns Void + */ +Void TEncSbac::codeMergeIndex( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + UInt uiUnaryIdx = pcCU->getMergeIndex( uiAbsPartIdx ); + UInt uiNumCand = pcCU->getSlice()->getMaxNumMergeCand(); + if ( uiNumCand > 1 ) + { + for( UInt ui = 0; ui < uiNumCand - 1; ++ui ) + { + const UInt uiSymbol = ui == uiUnaryIdx ? 0 : 1; + if ( ui==0 ) + { + m_pcBinIf->encodeBin( uiSymbol, m_cCUMergeIdxExtSCModel.get( 0, 0, 0 ) ); + } + else + { + m_pcBinIf->encodeBinEP( uiSymbol ); + } + if( uiSymbol == 0 ) + { + break; + } + } + } + DTRACE_CABAC_VL( g_nSymbolCounter++ ); + DTRACE_CABAC_T( "\tparseMergeIndex()" ); + DTRACE_CABAC_T( "\tuiMRGIdx= " ); + DTRACE_CABAC_V( pcCU->getMergeIndex( uiAbsPartIdx ) ); + DTRACE_CABAC_T( "\n" ); +} + +Void TEncSbac::codeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) +{ + if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth ) + return; + + UInt uiCtx = pcCU->getCtxSplitFlag( uiAbsPartIdx, uiDepth ); + UInt uiCurrSplitFlag = ( pcCU->getDepth( uiAbsPartIdx ) > uiDepth ) ? 1 : 0; + + assert( uiCtx < 3 ); + m_pcBinIf->encodeBin( uiCurrSplitFlag, m_cCUSplitFlagSCModel.get( 0, 0, uiCtx ) ); + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tSplitFlag\n" ) + return; +} + +Void TEncSbac::codeTransformSubdivFlag( UInt uiSymbol, UInt uiCtx ) +{ + m_pcBinIf->encodeBin( uiSymbol, m_cCUTransSubdivFlagSCModel.get( 0, 0, uiCtx ) ); + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tparseTransformSubdivFlag()" ) + DTRACE_CABAC_T( "\tsymbol=" ) + DTRACE_CABAC_V( uiSymbol ) + DTRACE_CABAC_T( "\tctx=" ) + DTRACE_CABAC_V( uiCtx ) + DTRACE_CABAC_T( "\n" ) +} + + +Void TEncSbac::codeIntraDirLumaAng( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiple) +{ + UInt dir[4],j; + Int preds[4][NUM_MOST_PROBABLE_MODES] = {{-1, -1, -1},{-1, -1, -1},{-1, -1, -1},{-1, -1, -1}}; + Int predNum[4], predIdx[4] ={ -1,-1,-1,-1}; + PartSize mode = pcCU->getPartitionSize( absPartIdx ); + UInt partNum = isMultiple?(mode==SIZE_NxN?4:1):1; + UInt partOffset = ( pcCU->getPic()->getNumPartitionsInCtu() >> ( pcCU->getDepth(absPartIdx) << 1 ) ) >> 2; + for (j=0;jgetIntraDir( CHANNEL_TYPE_LUMA, absPartIdx+partOffset*j ); + predNum[j] = pcCU->getIntraDirPredictor(absPartIdx+partOffset*j, preds[j], COMPONENT_Y); + for(UInt i = 0; i < predNum[j]; i++) + { + if(dir[j] == preds[j][i]) + { + predIdx[j] = i; + } + } + m_pcBinIf->encodeBin((predIdx[j] != -1)? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, 0 ) ); + } + for (j=0;jencodeBinEP( predIdx[j] ? 1 : 0 ); + if (predIdx[j]) + { + m_pcBinIf->encodeBinEP( predIdx[j]-1 ); + } + } + else + { + assert(predNum[j]>=3); // It is currently always 3! + if (preds[j][0] > preds[j][1]) + { + std::swap(preds[j][0], preds[j][1]); + } + if (preds[j][0] > preds[j][2]) + { + std::swap(preds[j][0], preds[j][2]); + } + if (preds[j][1] > preds[j][2]) + { + std::swap(preds[j][1], preds[j][2]); + } + for(Int i = (predNum[j] - 1); i >= 0; i--) + { + dir[j] = dir[j] > preds[j][i] ? dir[j] - 1 : dir[j]; + } + m_pcBinIf->encodeBinsEP( dir[j], 5 ); + } + } + return; +} + +Void TEncSbac::codeIntraDirChroma( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + UInt uiIntraDirChroma = pcCU->getIntraDir( CHANNEL_TYPE_CHROMA, uiAbsPartIdx ); + + if( uiIntraDirChroma == DM_CHROMA_IDX ) + { + m_pcBinIf->encodeBin( 0, m_cCUChromaPredSCModel.get( 0, 0, 0 ) ); + } + else + { + m_pcBinIf->encodeBin( 1, m_cCUChromaPredSCModel.get( 0, 0, 0 ) ); + + UInt uiAllowedChromaDir[ NUM_CHROMA_MODE ]; + pcCU->getAllowedChromaDir( uiAbsPartIdx, uiAllowedChromaDir ); + + for( Int i = 0; i < NUM_CHROMA_MODE - 1; i++ ) + { + if( uiIntraDirChroma == uiAllowedChromaDir[i] ) + { + uiIntraDirChroma = i; + break; + } + } + + m_pcBinIf->encodeBinsEP( uiIntraDirChroma, 2 ); + } + + return; +} + + +Void TEncSbac::codeInterDir( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + const UInt uiInterDir = pcCU->getInterDir( uiAbsPartIdx ) - 1; + const UInt uiCtx = pcCU->getCtxInterDir( uiAbsPartIdx ); + ContextModel *pCtx = m_cCUInterDirSCModel.get( 0 ); + + if (pcCU->getPartitionSize(uiAbsPartIdx) == SIZE_2Nx2N || pcCU->getHeight(uiAbsPartIdx) != 8 ) + { + m_pcBinIf->encodeBin( uiInterDir == 2 ? 1 : 0, *( pCtx + uiCtx ) ); + } + + if (uiInterDir < 2) + { + m_pcBinIf->encodeBin( uiInterDir, *( pCtx + 4 ) ); + } + + return; +} + +Void TEncSbac::codeRefFrmIdx( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + Int iRefFrame = pcCU->getCUMvField( eRefList )->getRefIdx( uiAbsPartIdx ); + ContextModel *pCtx = m_cCURefPicSCModel.get( 0 ); + m_pcBinIf->encodeBin( ( iRefFrame == 0 ? 0 : 1 ), *pCtx ); + + if( iRefFrame > 0 ) + { + UInt uiRefNum = pcCU->getSlice()->getNumRefIdx( eRefList ) - 2; + pCtx++; + iRefFrame--; + for( UInt ui = 0; ui < uiRefNum; ++ui ) + { + const UInt uiSymbol = ui == iRefFrame ? 0 : 1; + if( ui == 0 ) + { + m_pcBinIf->encodeBin( uiSymbol, *pCtx ); + } + else + { + m_pcBinIf->encodeBinEP( uiSymbol ); + } + if( uiSymbol == 0 ) + { + break; + } + } + } + return; +} + +Void TEncSbac::codeMvd( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefList ) +{ + if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefList == REF_PIC_LIST_1 && pcCU->getInterDir(uiAbsPartIdx)==3) + { + return; + } + + const TComCUMvField* pcCUMvField = pcCU->getCUMvField( eRefList ); + const Int iHor = pcCUMvField->getMvd( uiAbsPartIdx ).getHor(); + const Int iVer = pcCUMvField->getMvd( uiAbsPartIdx ).getVer(); + ContextModel* pCtx = m_cCUMvdSCModel.get( 0 ); + + m_pcBinIf->encodeBin( iHor != 0 ? 1 : 0, *pCtx ); + m_pcBinIf->encodeBin( iVer != 0 ? 1 : 0, *pCtx ); + + const Bool bHorAbsGr0 = iHor != 0; + const Bool bVerAbsGr0 = iVer != 0; + const UInt uiHorAbs = 0 > iHor ? -iHor : iHor; + const UInt uiVerAbs = 0 > iVer ? -iVer : iVer; + pCtx++; + + if( bHorAbsGr0 ) + { + m_pcBinIf->encodeBin( uiHorAbs > 1 ? 1 : 0, *pCtx ); + } + + if( bVerAbsGr0 ) + { + m_pcBinIf->encodeBin( uiVerAbs > 1 ? 1 : 0, *pCtx ); + } + + if( bHorAbsGr0 ) + { + if( uiHorAbs > 1 ) + { + xWriteEpExGolomb( uiHorAbs-2, 1 ); + } + + m_pcBinIf->encodeBinEP( 0 > iHor ? 1 : 0 ); + } + + if( bVerAbsGr0 ) + { + if( uiVerAbs > 1 ) + { + xWriteEpExGolomb( uiVerAbs-2, 1 ); + } + + m_pcBinIf->encodeBinEP( 0 > iVer ? 1 : 0 ); + } + + return; +} + +Void TEncSbac::codeCrossComponentPrediction( TComTU &rTu, ComponentID compID ) +{ + TComDataCU *pcCU = rTu.getCU(); + + if( isLuma(compID) || !pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction() ) return; + + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + + if (!pcCU->isIntra(uiAbsPartIdx) || (pcCU->getIntraDir( CHANNEL_TYPE_CHROMA, uiAbsPartIdx ) == DM_CHROMA_IDX)) + { + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T("\tparseCrossComponentPrediction()") + DTRACE_CABAC_T( "\tAddr=" ) + DTRACE_CABAC_V( compID ) + DTRACE_CABAC_T( "\tuiAbsPartIdx=" ) + DTRACE_CABAC_V( uiAbsPartIdx ) + + Int alpha = pcCU->getCrossComponentPredictionAlpha( uiAbsPartIdx, compID ); + ContextModel *pCtx = m_cCrossComponentPredictionSCModel.get(0, 0) + ((compID == COMPONENT_Cr) ? (NUM_CROSS_COMPONENT_PREDICTION_CTX >> 1) : 0); + m_pcBinIf->encodeBin(((alpha != 0) ? 1 : 0), pCtx[0]); + + if (alpha != 0) + { + static const Int log2AbsAlphaMinus1Table[8] = { 0, 1, 1, 2, 2, 2, 3, 3 }; + assert(abs(alpha) <= 8); + + if (abs(alpha)>1) + { + m_pcBinIf->encodeBin(1, pCtx[1]); + xWriteUnaryMaxSymbol( log2AbsAlphaMinus1Table[abs(alpha) - 1] - 1, (pCtx + 2), 1, 2 ); + } + else + { + m_pcBinIf->encodeBin(0, pCtx[1]); + } + m_pcBinIf->encodeBin( ((alpha < 0) ? 1 : 0), pCtx[4] ); + } + DTRACE_CABAC_T( "\tAlpha=" ) + DTRACE_CABAC_V( pcCU->getCrossComponentPredictionAlpha( uiAbsPartIdx, compID ) ) + DTRACE_CABAC_T( "\n" ) + } +} + +Void TEncSbac::codeDeltaQP( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + Int iDQp = pcCU->getQP( uiAbsPartIdx ) - pcCU->getRefQP( uiAbsPartIdx ); + + Int qpBdOffsetY = pcCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA); + iDQp = (iDQp + 78 + qpBdOffsetY + (qpBdOffsetY/2)) % (52 + qpBdOffsetY) - 26 - (qpBdOffsetY/2); + + UInt uiAbsDQp = (UInt)((iDQp > 0)? iDQp : (-iDQp)); + UInt TUValue = min((Int)uiAbsDQp, CU_DQP_TU_CMAX); + xWriteUnaryMaxSymbol( TUValue, &m_cCUDeltaQpSCModel.get( 0, 0, 0 ), 1, CU_DQP_TU_CMAX); + if( uiAbsDQp >= CU_DQP_TU_CMAX ) + { + xWriteEpExGolomb( uiAbsDQp - CU_DQP_TU_CMAX, CU_DQP_EG_k ); + } + + if ( uiAbsDQp > 0) + { + UInt uiSign = (iDQp > 0 ? 0 : 1); + m_pcBinIf->encodeBinEP(uiSign); + } + + return; +} + +/** code chroma qp adjustment, converting from the internal table representation + * \returns Void + */ +Void TEncSbac::codeChromaQpAdjustment( TComDataCU* cu, UInt absPartIdx ) +{ + Int internalIdc = cu->getChromaQpAdj( absPartIdx ); + Int tableSize = cu->getSlice()->getPPS()->getChromaQpAdjTableSize(); + /* internal_idc == 0 => flag = 0 + * internal_idc > 1 => code idc value (if table size warrents) */ + m_pcBinIf->encodeBin( internalIdc > 0, m_ChromaQpAdjFlagSCModel.get( 0, 0, 0 ) ); + + if (internalIdc > 0 && tableSize > 1) + { + xWriteUnaryMaxSymbol( internalIdc - 1, &m_ChromaQpAdjIdcSCModel.get( 0, 0, 0 ), 0, tableSize - 1 ); + } +} + +Void TEncSbac::codeQtCbf( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ) +{ + TComDataCU* pcCU = rTu.getCU(); + + const UInt absPartIdx = rTu.GetAbsPartIdxTU(compID); + const UInt TUDepth = rTu.GetTransformDepthRel(); + UInt uiCtx = pcCU->getCtxQtCbf( rTu, toChannelType(compID) ); + const UInt contextSet = toChannelType(compID); + + const UInt width = rTu.getRect(compID).width; + const UInt height = rTu.getRect(compID).height; + const Bool canQuadSplit = (width >= (MIN_TU_SIZE * 2)) && (height >= (MIN_TU_SIZE * 2)); + + // Since the CBF for chroma is coded at the highest level possible, if sub-TUs are + // to be coded for a 4x8 chroma TU, their CBFs must be coded at the highest 4x8 level + // (i.e. where luma TUs are 8x8 rather than 4x4) + // ___ ___ + // | | | <- 4 x (8x8 luma + 4x8 4:2:2 chroma) + // |___|___| each quadrant has its own chroma CBF + // | | | _ _ _ _ + // |___|___| | + // <--16---> V + // _ _ + // |_|_| <- 4 x 4x4 luma + 1 x 4x8 4:2:2 chroma + // |_|_| no chroma CBF is coded - instead the parent CBF is inherited + // <-8-> if sub-TUs are present, their CBFs had to be coded at the parent level + + const UInt lowestTUDepth = TUDepth + ((!lowestLevel && !canQuadSplit) ? 1 : 0); //unsplittable TUs inherit their parent's CBF + + if ((width != height) && (lowestLevel || !canQuadSplit)) //if sub-TUs are present + { + const UInt subTUDepth = lowestTUDepth + 1; //if this is the lowest level of the TU-tree, the sub-TUs are directly below. Otherwise, this must be the level above the lowest level (as specified above) + const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> 1; + + for (UInt subTU = 0; subTU < 2; subTU++) + { + const UInt subTUAbsPartIdx = absPartIdx + (subTU * partIdxesPerSubTU); + const UInt uiCbf = pcCU->getCbf(subTUAbsPartIdx, compID, subTUDepth); + + m_pcBinIf->encodeBin(uiCbf, m_cCUQtCbfSCModel.get(0, contextSet, uiCtx)); + + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tparseQtCbf()" ) + DTRACE_CABAC_T( "\tsub-TU=" ) + DTRACE_CABAC_V( subTU ) + DTRACE_CABAC_T( "\tsymbol=" ) + DTRACE_CABAC_V( uiCbf ) + DTRACE_CABAC_T( "\tctx=" ) + DTRACE_CABAC_V( uiCtx ) + DTRACE_CABAC_T( "\tetype=" ) + DTRACE_CABAC_V( compID ) + DTRACE_CABAC_T( "\tuiAbsPartIdx=" ) + DTRACE_CABAC_V( subTUAbsPartIdx ) + DTRACE_CABAC_T( "\n" ) + } + } + else + { + const UInt uiCbf = pcCU->getCbf( absPartIdx, compID, lowestTUDepth ); + m_pcBinIf->encodeBin( uiCbf , m_cCUQtCbfSCModel.get( 0, contextSet, uiCtx ) ); + + + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tparseQtCbf()" ) + DTRACE_CABAC_T( "\tsymbol=" ) + DTRACE_CABAC_V( uiCbf ) + DTRACE_CABAC_T( "\tctx=" ) + DTRACE_CABAC_V( uiCtx ) + DTRACE_CABAC_T( "\tetype=" ) + DTRACE_CABAC_V( compID ) + DTRACE_CABAC_T( "\tuiAbsPartIdx=" ) + DTRACE_CABAC_V( rTu.GetAbsPartIdxTU(compID) ) + DTRACE_CABAC_T( "\n" ) + } +} + + +Void TEncSbac::codeTransformSkipFlags (TComTU &rTu, ComponentID component ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + + if (pcCU->getCUTransquantBypass(uiAbsPartIdx)) + { + return; + } + + if (!TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(component), pcCU->getSlice()->getPPS()->getTransformSkipLog2MaxSize())) + { + return; + } + + UInt useTransformSkip = pcCU->getTransformSkip( uiAbsPartIdx,component); + m_pcBinIf->encodeBin( useTransformSkip, m_cTransformSkipSCModel.get( 0, toChannelType(component), 0 ) ); + + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T("\tparseTransformSkip()"); + DTRACE_CABAC_T( "\tsymbol=" ) + DTRACE_CABAC_V( useTransformSkip ) + DTRACE_CABAC_T( "\tAddr=" ) + DTRACE_CABAC_V( pcCU->getCtuRsAddr() ) + DTRACE_CABAC_T( "\tetype=" ) + DTRACE_CABAC_V( component ) + DTRACE_CABAC_T( "\tuiAbsPartIdx=" ) + DTRACE_CABAC_V( rTu.GetAbsPartIdxTU() ) + DTRACE_CABAC_T( "\n" ) +} + + +/** Code I_PCM information. + * \param pcCU pointer to CU + * \param uiAbsPartIdx CU index + * \returns Void + */ +Void TEncSbac::codeIPCMInfo( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + UInt uiIPCM = (pcCU->getIPCMFlag(uiAbsPartIdx) == true)? 1 : 0; + + Bool writePCMSampleFlag = pcCU->getIPCMFlag(uiAbsPartIdx); + + m_pcBinIf->encodeBinTrm (uiIPCM); + + if (writePCMSampleFlag) + { + m_pcBinIf->encodePCMAlignBits(); + + const UInt minCoeffSizeY = pcCU->getPic()->getMinCUWidth() * pcCU->getPic()->getMinCUHeight(); + const UInt offsetY = minCoeffSizeY * uiAbsPartIdx; + for (UInt ch=0; ch < pcCU->getPic()->getNumberValidComponents(); ch++) + { + const ComponentID compID = ComponentID(ch); + const UInt offset = offsetY >> (pcCU->getPic()->getComponentScaleX(compID) + pcCU->getPic()->getComponentScaleY(compID)); + Pel * pPCMSample = pcCU->getPCMSample(compID) + offset; + const UInt width = pcCU->getWidth (uiAbsPartIdx) >> pcCU->getPic()->getComponentScaleX(compID); + const UInt height = pcCU->getHeight(uiAbsPartIdx) >> pcCU->getPic()->getComponentScaleY(compID); + const UInt sampleBits = pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID)); + for (UInt y=0; yxWritePCMCode(sample, sampleBits); + } + pPCMSample += width; + } + } + + m_pcBinIf->resetBac(); + } +} + +Void TEncSbac::codeQtRootCbf( TComDataCU* pcCU, UInt uiAbsPartIdx ) +{ + UInt uiCbf = pcCU->getQtRootCbf( uiAbsPartIdx ); + UInt uiCtx = 0; + m_pcBinIf->encodeBin( uiCbf , m_cCUQtRootCbfSCModel.get( 0, 0, uiCtx ) ); + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tparseQtRootCbf()" ) + DTRACE_CABAC_T( "\tsymbol=" ) + DTRACE_CABAC_V( uiCbf ) + DTRACE_CABAC_T( "\tctx=" ) + DTRACE_CABAC_V( uiCtx ) + DTRACE_CABAC_T( "\tuiAbsPartIdx=" ) + DTRACE_CABAC_V( uiAbsPartIdx ) + DTRACE_CABAC_T( "\n" ) +} + +Void TEncSbac::codeQtCbfZero( TComTU & rTu, const ChannelType chType ) +{ + // this function is only used to estimate the bits when cbf is 0 + // and will never be called when writing the bistream. do not need to write log + UInt uiCbf = 0; + UInt uiCtx = rTu.getCU()->getCtxQtCbf( rTu, chType ); + + m_pcBinIf->encodeBin( uiCbf , m_cCUQtCbfSCModel.get( 0, chType, uiCtx ) ); +} + +Void TEncSbac::codeQtRootCbfZero( TComDataCU* pcCU ) +{ + // this function is only used to estimate the bits when cbf is 0 + // and will never be called when writing the bistream. do not need to write log + UInt uiCbf = 0; + UInt uiCtx = 0; + m_pcBinIf->encodeBin( uiCbf , m_cCUQtRootCbfSCModel.get( 0, 0, uiCtx ) ); +} + +/** Encode (X,Y) position of the last significant coefficient + * \param uiPosX X component of last coefficient + * \param uiPosY Y component of last coefficient + * \param width Block width + * \param height Block height + * \param eTType plane type / luminance or chrominance + * \param uiScanIdx scan type (zig-zag, hor, ver) + * This method encodes the X and Y component within a block of the last significant coefficient. + */ +Void TEncSbac::codeLastSignificantXY( UInt uiPosX, UInt uiPosY, Int width, Int height, ComponentID component, UInt uiScanIdx ) +{ + // swap + if( uiScanIdx == SCAN_VER ) + { + swap( uiPosX, uiPosY ); + swap( width, height ); + } + + UInt uiCtxLast; + UInt uiGroupIdxX = g_uiGroupIdx[ uiPosX ]; + UInt uiGroupIdxY = g_uiGroupIdx[ uiPosY ]; + + ContextModel *pCtxX = m_cCuCtxLastX.get( 0, toChannelType(component) ); + ContextModel *pCtxY = m_cCuCtxLastY.get( 0, toChannelType(component) ); + + Int blkSizeOffsetX, blkSizeOffsetY, shiftX, shiftY; + getLastSignificantContextParameters(component, width, height, blkSizeOffsetX, blkSizeOffsetY, shiftX, shiftY); + + //------------------ + + // posX + + for( uiCtxLast = 0; uiCtxLast < uiGroupIdxX; uiCtxLast++ ) + { + m_pcBinIf->encodeBin( 1, *( pCtxX + blkSizeOffsetX + (uiCtxLast >>shiftX) ) ); + } + if( uiGroupIdxX < g_uiGroupIdx[ width - 1 ]) + { + m_pcBinIf->encodeBin( 0, *( pCtxX + blkSizeOffsetX + (uiCtxLast >>shiftX) ) ); + } + + // posY + + for( uiCtxLast = 0; uiCtxLast < uiGroupIdxY; uiCtxLast++ ) + { + m_pcBinIf->encodeBin( 1, *( pCtxY + blkSizeOffsetY + (uiCtxLast >>shiftY) ) ); + } + if( uiGroupIdxY < g_uiGroupIdx[ height - 1 ]) + { + m_pcBinIf->encodeBin( 0, *( pCtxY + blkSizeOffsetY + (uiCtxLast >>shiftY) ) ); + } + + // EP-coded part + + if ( uiGroupIdxX > 3 ) + { + UInt uiCount = ( uiGroupIdxX - 2 ) >> 1; + uiPosX = uiPosX - g_uiMinInGroup[ uiGroupIdxX ]; + for (Int i = uiCount - 1 ; i >= 0; i-- ) + { + m_pcBinIf->encodeBinEP( ( uiPosX >> i ) & 1 ); + } + } + if ( uiGroupIdxY > 3 ) + { + UInt uiCount = ( uiGroupIdxY - 2 ) >> 1; + uiPosY = uiPosY - g_uiMinInGroup[ uiGroupIdxY ]; + for ( Int i = uiCount - 1 ; i >= 0; i-- ) + { + m_pcBinIf->encodeBinEP( ( uiPosY >> i ) & 1 ); + } + } +} + + +Void TEncSbac::codeCoeffNxN( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(compID); + const TComRectangle &tuRect=rTu.getRect(compID); + const UInt uiWidth=tuRect.width; + const UInt uiHeight=tuRect.height; + + DTRACE_CABAC_VL( g_nSymbolCounter++ ) + DTRACE_CABAC_T( "\tparseCoeffNxN()\teType=" ) + DTRACE_CABAC_V( compID ) + DTRACE_CABAC_T( "\twidth=" ) + DTRACE_CABAC_V( uiWidth ) + DTRACE_CABAC_T( "\theight=" ) + DTRACE_CABAC_V( uiHeight ) + DTRACE_CABAC_T( "\tdepth=" ) +// DTRACE_CABAC_V( rTu.GetTransformDepthTotalAdj(compID) ) + DTRACE_CABAC_V( rTu.GetTransformDepthTotal() ) + DTRACE_CABAC_T( "\tabspartidx=" ) + DTRACE_CABAC_V( uiAbsPartIdx ) + DTRACE_CABAC_T( "\ttoCU-X=" ) + DTRACE_CABAC_V( pcCU->getCUPelX() ) + DTRACE_CABAC_T( "\ttoCU-Y=" ) + DTRACE_CABAC_V( pcCU->getCUPelY() ) + DTRACE_CABAC_T( "\tCU-addr=" ) + DTRACE_CABAC_V( pcCU->getCtuRsAddr() ) + DTRACE_CABAC_T( "\tinCU-X=" ) +// DTRACE_CABAC_V( g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ] ) + DTRACE_CABAC_V( g_auiRasterToPelX[ g_auiZscanToRaster[rTu.GetAbsPartIdxTU(compID)] ] ) + DTRACE_CABAC_T( "\tinCU-Y=" ) +// DTRACE_CABAC_V( g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ] ) + DTRACE_CABAC_V( g_auiRasterToPelY[ g_auiZscanToRaster[rTu.GetAbsPartIdxTU(compID)] ] ) + DTRACE_CABAC_T( "\tpredmode=" ) + DTRACE_CABAC_V( pcCU->getPredictionMode( uiAbsPartIdx ) ) + DTRACE_CABAC_T( "\n" ) + + //-------------------------------------------------------------------------------------------------- + + if( uiWidth > m_pcSlice->getSPS()->getMaxTrSize() ) + { + std::cerr << "ERROR: codeCoeffNxN was passed a TU with dimensions larger than the maximum allowed size" << std::endl; + assert(false); + exit(1); + } + + // compute number of significant coefficients + UInt uiNumSig = TEncEntropy::countNonZeroCoeffs(pcCoef, uiWidth * uiHeight); + + if ( uiNumSig == 0 ) + { + std::cerr << "ERROR: codeCoeffNxN called for empty TU!" << std::endl; + assert(false); + exit(1); + } + + //-------------------------------------------------------------------------------------------------- + + //set parameters + + const ChannelType chType = toChannelType(compID); + const UInt uiLog2BlockWidth = g_aucConvertToBit[ uiWidth ] + 2; + const UInt uiLog2BlockHeight = g_aucConvertToBit[ uiHeight ] + 2; + + const ChannelType channelType = toChannelType(compID); + const Bool extendedPrecision = pcCU->getSlice()->getSPS()->getUseExtendedPrecision(); + + const Bool alignCABACBeforeBypass = pcCU->getSlice()->getSPS()->getAlignCABACBeforeBypass(); + + Bool beValid; + + { + Int uiIntraMode = -1; + const Bool bIsLuma = isLuma(compID); + Int isIntra = pcCU->isIntra(uiAbsPartIdx) ? 1 : 0; + if ( isIntra ) + { + uiIntraMode = pcCU->getIntraDir( toChannelType(compID), uiAbsPartIdx ); + + uiIntraMode = (uiIntraMode==DM_CHROMA_IDX && !bIsLuma) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, rTu.GetChromaFormat())) : uiIntraMode; + uiIntraMode = ((rTu.GetChromaFormat() == CHROMA_422) && !bIsLuma) ? g_chroma422IntraAngleMappingTable[uiIntraMode] : uiIntraMode; + } + + Int transformSkip = pcCU->getTransformSkip( uiAbsPartIdx,compID) ? 1 : 0; + Bool rdpcm_lossy = ( transformSkip && isIntra && ( (uiIntraMode == HOR_IDX) || (uiIntraMode == VER_IDX) ) ) && pcCU->isRDPCMEnabled(uiAbsPartIdx); + + if ( (pcCU->getCUTransquantBypass(uiAbsPartIdx)) || rdpcm_lossy ) + { + beValid = false; + if ( (!pcCU->isIntra(uiAbsPartIdx)) && pcCU->isRDPCMEnabled(uiAbsPartIdx)) + codeExplicitRdpcmMode( rTu, compID); + } + else + { + beValid = pcCU->getSlice()->getPPS()->getSignHideFlag() > 0; + } + } + + //-------------------------------------------------------------------------------------------------- + + if(pcCU->getSlice()->getPPS()->getUseTransformSkip()) + { + codeTransformSkipFlags(rTu, compID); + if(pcCU->getTransformSkip(uiAbsPartIdx, compID) && !pcCU->isIntra(uiAbsPartIdx) && pcCU->isRDPCMEnabled(uiAbsPartIdx)) + { + // This TU has coefficients and is transform skipped. Check whether is inter coded and if yes encode the explicit RDPCM mode + codeExplicitRdpcmMode( rTu, compID); + + if(pcCU->getExplicitRdpcmMode(compID, uiAbsPartIdx) != RDPCM_OFF) + { + // Sign data hiding is avoided for horizontal and vertical explicit RDPCM modes + beValid = false; + } + } + } + + //-------------------------------------------------------------------------------------------------- + + const Bool bUseGolombRiceParameterAdaptation = pcCU->getSlice()->getSPS()->getUseGolombRiceParameterAdaptation(); + UInt ¤tGolombRiceStatistic = m_golombRiceAdaptationStatistics[rTu.getGolombRiceStatisticsIndex(compID)]; + + //select scans + TUEntropyCodingParameters codingParameters; + getTUEntropyCodingParameters(codingParameters, rTu, compID); + + //----- encode significance map ----- + + // Find position of last coefficient + Int scanPosLast = -1; + Int posLast; + + + UInt uiSigCoeffGroupFlag[ MLS_GRP_NUM ]; + + memset( uiSigCoeffGroupFlag, 0, sizeof(UInt) * MLS_GRP_NUM ); + do + { + posLast = codingParameters.scan[ ++scanPosLast ]; + + if( pcCoef[ posLast ] != 0 ) + { + // get L1 sig map + UInt uiPosY = posLast >> uiLog2BlockWidth; + UInt uiPosX = posLast - ( uiPosY << uiLog2BlockWidth ); + + UInt uiBlkIdx = (codingParameters.widthInGroups * (uiPosY >> MLS_CG_LOG2_HEIGHT)) + (uiPosX >> MLS_CG_LOG2_WIDTH); + uiSigCoeffGroupFlag[ uiBlkIdx ] = 1; + + uiNumSig--; + } + } + while ( uiNumSig > 0 ); + + // Code position of last coefficient + Int posLastY = posLast >> uiLog2BlockWidth; + Int posLastX = posLast - ( posLastY << uiLog2BlockWidth ); + codeLastSignificantXY(posLastX, posLastY, uiWidth, uiHeight, compID, codingParameters.scanType); + + //===== code significance flag ===== + ContextModel * const baseCoeffGroupCtx = m_cCUSigCoeffGroupSCModel.get( 0, chType ); + ContextModel * const baseCtx = m_cCUSigSCModel.get( 0, 0 ) + getSignificanceMapContextOffset(compID); + + const Int iLastScanSet = scanPosLast >> MLS_CG_SIZE; + + UInt c1 = 1; + UInt uiGoRiceParam = 0; + Int iScanPosSig = scanPosLast; + + for( Int iSubSet = iLastScanSet; iSubSet >= 0; iSubSet-- ) + { + Int numNonZero = 0; + Int iSubPos = iSubSet << MLS_CG_SIZE; + uiGoRiceParam = currentGolombRiceStatistic / RExt__GOLOMB_RICE_INCREMENT_DIVISOR; + Bool updateGolombRiceStatistics = bUseGolombRiceParameterAdaptation; //leave the statistics at 0 when not using the adaptation system + UInt coeffSigns = 0; + + Int absCoeff[1 << MLS_CG_SIZE]; + + Int lastNZPosInCG = -1; + Int firstNZPosInCG = 1 << MLS_CG_SIZE; + + Bool escapeDataPresentInGroup = false; + + if( iScanPosSig == scanPosLast ) + { + absCoeff[ 0 ] = Int(abs( pcCoef[ posLast ] )); + coeffSigns = ( pcCoef[ posLast ] < 0 ); + numNonZero = 1; + lastNZPosInCG = iScanPosSig; + firstNZPosInCG = iScanPosSig; + iScanPosSig--; + } + + // encode significant_coeffgroup_flag + Int iCGBlkPos = codingParameters.scanCG[ iSubSet ]; + Int iCGPosY = iCGBlkPos / codingParameters.widthInGroups; + Int iCGPosX = iCGBlkPos - (iCGPosY * codingParameters.widthInGroups); + + if( iSubSet == iLastScanSet || iSubSet == 0) + { + uiSigCoeffGroupFlag[ iCGBlkPos ] = 1; + } + else + { + UInt uiSigCoeffGroup = (uiSigCoeffGroupFlag[ iCGBlkPos ] != 0); + UInt uiCtxSig = TComTrQuant::getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, iCGPosX, iCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups ); + m_pcBinIf->encodeBin( uiSigCoeffGroup, baseCoeffGroupCtx[ uiCtxSig ] ); + } + + // encode significant_coeff_flag + if( uiSigCoeffGroupFlag[ iCGBlkPos ] ) + { + const Int patternSigCtx = TComTrQuant::calcPatternSigCtx(uiSigCoeffGroupFlag, iCGPosX, iCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups); + + UInt uiBlkPos, uiSig, uiCtxSig; + for( ; iScanPosSig >= iSubPos; iScanPosSig-- ) + { + uiBlkPos = codingParameters.scan[ iScanPosSig ]; + uiSig = (pcCoef[ uiBlkPos ] != 0); + if( iScanPosSig > iSubPos || iSubSet == 0 || numNonZero ) + { + uiCtxSig = TComTrQuant::getSigCtxInc( patternSigCtx, codingParameters, iScanPosSig, uiLog2BlockWidth, uiLog2BlockHeight, chType ); + m_pcBinIf->encodeBin( uiSig, baseCtx[ uiCtxSig ] ); + } + if( uiSig ) + { + absCoeff[ numNonZero ] = Int(abs( pcCoef[ uiBlkPos ] )); + coeffSigns = 2 * coeffSigns + ( pcCoef[ uiBlkPos ] < 0 ); + numNonZero++; + if( lastNZPosInCG == -1 ) + { + lastNZPosInCG = iScanPosSig; + } + firstNZPosInCG = iScanPosSig; + } + } + } + else + { + iScanPosSig = iSubPos - 1; + } + + if( numNonZero > 0 ) + { + Bool signHidden = ( lastNZPosInCG - firstNZPosInCG >= SBH_THRESHOLD ); + + const UInt uiCtxSet = getContextSetIndex(compID, iSubSet, (c1 == 0)); + c1 = 1; + + ContextModel *baseCtxMod = m_cCUOneSCModel.get( 0, 0 ) + (NUM_ONE_FLAG_CTX_PER_SET * uiCtxSet); + + Int numC1Flag = min(numNonZero, C1FLAG_NUMBER); + Int firstC2FlagIdx = -1; + for( Int idx = 0; idx < numC1Flag; idx++ ) + { + UInt uiSymbol = absCoeff[ idx ] > 1; + m_pcBinIf->encodeBin( uiSymbol, baseCtxMod[c1] ); + if( uiSymbol ) + { + c1 = 0; + + if (firstC2FlagIdx == -1) + { + firstC2FlagIdx = idx; + } + else //if a greater-than-one has been encountered already this group + { + escapeDataPresentInGroup = true; + } + } + else if( (c1 < 3) && (c1 > 0) ) + { + c1++; + } + } + + if (c1 == 0) + { + baseCtxMod = m_cCUAbsSCModel.get( 0, 0 ) + (NUM_ABS_FLAG_CTX_PER_SET * uiCtxSet); + if ( firstC2FlagIdx != -1) + { + UInt symbol = absCoeff[ firstC2FlagIdx ] > 2; + m_pcBinIf->encodeBin( symbol, baseCtxMod[0] ); + if (symbol != 0) + { + escapeDataPresentInGroup = true; + } + } + } + + escapeDataPresentInGroup = escapeDataPresentInGroup || (numNonZero > C1FLAG_NUMBER); + + if (escapeDataPresentInGroup && alignCABACBeforeBypass) + { + m_pcBinIf->align(); + } + + if( beValid && signHidden ) + { + m_pcBinIf->encodeBinsEP( (coeffSigns >> 1), numNonZero-1 ); + } + else + { + m_pcBinIf->encodeBinsEP( coeffSigns, numNonZero ); + } + + Int iFirstCoeff2 = 1; + if (escapeDataPresentInGroup) + { + for ( Int idx = 0; idx < numNonZero; idx++ ) + { + UInt baseLevel = (idx < C1FLAG_NUMBER)? (2 + iFirstCoeff2 ) : 1; + + if( absCoeff[ idx ] >= baseLevel) + { + const UInt escapeCodeValue = absCoeff[idx] - baseLevel; + + xWriteCoefRemainExGolomb( escapeCodeValue, uiGoRiceParam, extendedPrecision, channelType ); + + if (absCoeff[idx] > (3 << uiGoRiceParam)) + { + uiGoRiceParam = bUseGolombRiceParameterAdaptation ? (uiGoRiceParam + 1) : (std::min((uiGoRiceParam + 1), 4)); + } + + if (updateGolombRiceStatistics) + { + const UInt initialGolombRiceParameter = currentGolombRiceStatistic / RExt__GOLOMB_RICE_INCREMENT_DIVISOR; + + if (escapeCodeValue >= (3 << initialGolombRiceParameter)) + { + currentGolombRiceStatistic++; + } + else if (((escapeCodeValue * 2) < (1 << initialGolombRiceParameter)) && (currentGolombRiceStatistic > 0)) + { + currentGolombRiceStatistic--; + } + + updateGolombRiceStatistics = false; + } + } + + if(absCoeff[ idx ] >= 2) + { + iFirstCoeff2 = 0; + } + } + } + } + } +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + printSBACCoeffData(posLastX, posLastY, uiWidth, uiHeight, compID, uiAbsPartIdx, codingParameters.scanType, pcCoef, g_bFinalEncode); +#endif + + return; +} + +/** code SAO offset sign + * \param code sign value + */ +Void TEncSbac::codeSAOSign( UInt code ) +{ + m_pcBinIf->encodeBinEP( code ); +} + +Void TEncSbac::codeSaoMaxUvlc ( UInt code, UInt maxSymbol ) +{ + if (maxSymbol == 0) + { + return; + } + + Int i; + Bool bCodeLast = ( maxSymbol > code ); + + if ( code == 0 ) + { + m_pcBinIf->encodeBinEP( 0 ); + } + else + { + m_pcBinIf->encodeBinEP( 1 ); + for ( i=0; iencodeBinEP( 1 ); + } + if( bCodeLast ) + { + m_pcBinIf->encodeBinEP( 0 ); + } + } +} + +/** Code SAO EO class or BO band position + * \param uiLength + * \param uiCode + */ +Void TEncSbac::codeSaoUflc ( UInt uiLength, UInt uiCode ) +{ + m_pcBinIf->encodeBinsEP ( uiCode, uiLength ); +} + +/** Code SAO merge flags + * \param uiCode + * \param uiCompIdx + */ +Void TEncSbac::codeSaoMerge ( UInt uiCode ) +{ + m_pcBinIf->encodeBin(((uiCode == 0) ? 0 : 1), m_cSaoMergeSCModel.get( 0, 0, 0 )); +} + +/** Code SAO type index + * \param uiCode + */ +Void TEncSbac::codeSaoTypeIdx ( UInt uiCode) +{ + if (uiCode == 0) + { + m_pcBinIf->encodeBin( 0, m_cSaoTypeIdxSCModel.get( 0, 0, 0 ) ); + } + else + { + m_pcBinIf->encodeBin( 1, m_cSaoTypeIdxSCModel.get( 0, 0, 0 ) ); + m_pcBinIf->encodeBinEP( uiCode == 1 ? 0 : 1 ); + } +} + +Void TEncSbac::codeSAOOffsetParam(ComponentID compIdx, SAOOffset& ctbParam, Bool sliceEnabled) +{ + UInt uiSymbol; + if(!sliceEnabled) + { + assert(ctbParam.modeIdc == SAO_MODE_OFF); + return; + } + const Bool bIsFirstCompOfChType = (getFirstComponentOfChannel(toChannelType(compIdx)) == compIdx); + + //type + if(bIsFirstCompOfChType) + { + //sao_type_idx_luma or sao_type_idx_chroma + if(ctbParam.modeIdc == SAO_MODE_OFF) + { + uiSymbol =0; + } + else if(ctbParam.typeIdc == SAO_TYPE_BO) //BO + { + uiSymbol = 1; + } + else + { + assert(ctbParam.typeIdc < SAO_TYPE_START_BO); //EO + uiSymbol = 2; + } + codeSaoTypeIdx(uiSymbol); + } + + if(ctbParam.modeIdc == SAO_MODE_NEW) + { + Int numClasses = (ctbParam.typeIdc == SAO_TYPE_BO)?4:NUM_SAO_EO_CLASSES; + Int offset[4]; + Int k=0; + for(Int i=0; i< numClasses; i++) + { + if(ctbParam.typeIdc != SAO_TYPE_BO && i == SAO_CLASS_EO_PLAIN) + { + continue; + } + Int classIdx = (ctbParam.typeIdc == SAO_TYPE_BO)?( (ctbParam.typeAuxInfo+i)% NUM_SAO_BO_CLASSES ):i; + offset[k] = ctbParam.offset[classIdx]; + k++; + } + + for(Int i=0; i< 4; i++) + { + codeSaoMaxUvlc((offset[i]<0)?(-offset[i]):(offset[i]), g_saoMaxOffsetQVal[compIdx] ); //sao_offset_abs + } + + + if(ctbParam.typeIdc == SAO_TYPE_BO) + { + for(Int i=0; i< 4; i++) + { + if(offset[i] != 0) + { + codeSAOSign((offset[i]< 0)?1:0); + } + } + + codeSaoUflc(NUM_SAO_BO_CLASSES_LOG2, ctbParam.typeAuxInfo ); //sao_band_position + } + else //EO + { + if(bIsFirstCompOfChType) + { + assert(ctbParam.typeIdc - SAO_TYPE_START_EO >=0); + codeSaoUflc(NUM_SAO_EO_TYPES_LOG2, ctbParam.typeIdc - SAO_TYPE_START_EO ); //sao_eo_class_luma or sao_eo_class_chroma + } + } + + } +} + + +Void TEncSbac::codeSAOBlkParam(SAOBlkParam& saoBlkParam + , Bool* sliceEnabled + , Bool leftMergeAvail + , Bool aboveMergeAvail + , Bool onlyEstMergeInfo // = false + ) +{ + + Bool isLeftMerge = false; + Bool isAboveMerge= false; + + if(leftMergeAvail) + { + isLeftMerge = ((saoBlkParam[COMPONENT_Y].modeIdc == SAO_MODE_MERGE) && (saoBlkParam[COMPONENT_Y].typeIdc == SAO_MERGE_LEFT)); + codeSaoMerge( isLeftMerge?1:0 ); //sao_merge_left_flag + } + + if( aboveMergeAvail && !isLeftMerge) + { + isAboveMerge = ((saoBlkParam[COMPONENT_Y].modeIdc == SAO_MODE_MERGE) && (saoBlkParam[COMPONENT_Y].typeIdc == SAO_MERGE_ABOVE)); + codeSaoMerge( isAboveMerge?1:0 ); //sao_merge_left_flag + } + + if(onlyEstMergeInfo) + { + return; //only for RDO + } + + if(!isLeftMerge && !isAboveMerge) //not merge mode + { + for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + codeSAOOffsetParam(ComponentID(compIdx), saoBlkParam[compIdx], sliceEnabled[compIdx]); + } + } +} + +/*! + **************************************************************************** + * \brief + * estimate bit cost for CBP, significant map and significant coefficients + **************************************************************************** + */ +Void TEncSbac::estBit( estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType ) +{ + estCBFBit( pcEstBitsSbac ); + + estSignificantCoeffGroupMapBit( pcEstBitsSbac, chType ); + + // encode significance map + estSignificantMapBit( pcEstBitsSbac, width, height, chType ); + + // encode last significant position + estLastSignificantPositionBit( pcEstBitsSbac, width, height, chType ); + + // encode significant coefficients + estSignificantCoefficientsBit( pcEstBitsSbac, chType ); + + memcpy(pcEstBitsSbac->golombRiceAdaptationStatistics, m_golombRiceAdaptationStatistics, (sizeof(UInt) * RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS)); +} + +/*! + **************************************************************************** + * \brief + * estimate bit cost for each CBP bit + **************************************************************************** + */ +Void TEncSbac::estCBFBit( estBitsSbacStruct* pcEstBitsSbac ) +{ + ContextModel *pCtx = m_cCUQtCbfSCModel.get( 0 ); + + for( UInt uiCtxInc = 0; uiCtxInc < (NUM_QT_CBF_CTX_SETS * NUM_QT_CBF_CTX_PER_SET); uiCtxInc++ ) + { + pcEstBitsSbac->blockCbpBits[ uiCtxInc ][ 0 ] = pCtx[ uiCtxInc ].getEntropyBits( 0 ); + pcEstBitsSbac->blockCbpBits[ uiCtxInc ][ 1 ] = pCtx[ uiCtxInc ].getEntropyBits( 1 ); + } + + pCtx = m_cCUQtRootCbfSCModel.get( 0 ); + + for( UInt uiCtxInc = 0; uiCtxInc < 4; uiCtxInc++ ) + { + pcEstBitsSbac->blockRootCbpBits[ uiCtxInc ][ 0 ] = pCtx[ uiCtxInc ].getEntropyBits( 0 ); + pcEstBitsSbac->blockRootCbpBits[ uiCtxInc ][ 1 ] = pCtx[ uiCtxInc ].getEntropyBits( 1 ); + } +} + + +/*! + **************************************************************************** + * \brief + * estimate SAMBAC bit cost for significant coefficient group map + **************************************************************************** + */ +Void TEncSbac::estSignificantCoeffGroupMapBit( estBitsSbacStruct* pcEstBitsSbac, ChannelType chType ) +{ + Int firstCtx = 0, numCtx = NUM_SIG_CG_FLAG_CTX; + + for ( Int ctxIdx = firstCtx; ctxIdx < firstCtx + numCtx; ctxIdx++ ) + { + for( UInt uiBin = 0; uiBin < 2; uiBin++ ) + { + pcEstBitsSbac->significantCoeffGroupBits[ ctxIdx ][ uiBin ] = m_cCUSigCoeffGroupSCModel.get( 0, chType, ctxIdx ).getEntropyBits( uiBin ); + } + } +} + + +/*! + **************************************************************************** + * \brief + * estimate SAMBAC bit cost for significant coefficient map + **************************************************************************** + */ +Void TEncSbac::estSignificantMapBit( estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType ) +{ + //-------------------------------------------------------------------------------------------------- + + //set up the number of channels and context variables + + const UInt firstComponent = ((isLuma(chType)) ? (COMPONENT_Y) : (COMPONENT_Cb)); + const UInt lastComponent = ((isLuma(chType)) ? (COMPONENT_Y) : (COMPONENT_Cb)); + + //---------------------------------------------------------- + + Int firstCtx = MAX_INT; + Int numCtx = MAX_INT; + + if ((width == 4) && (height == 4)) + { + firstCtx = significanceMapContextSetStart[chType][CONTEXT_TYPE_4x4]; + numCtx = significanceMapContextSetSize [chType][CONTEXT_TYPE_4x4]; + } + else if ((width == 8) && (height == 8)) + { + firstCtx = significanceMapContextSetStart[chType][CONTEXT_TYPE_8x8]; + numCtx = significanceMapContextSetSize [chType][CONTEXT_TYPE_8x8]; + } + else + { + firstCtx = significanceMapContextSetStart[chType][CONTEXT_TYPE_NxN]; + numCtx = significanceMapContextSetSize [chType][CONTEXT_TYPE_NxN]; + } + + //-------------------------------------------------------------------------------------------------- + + //fill the data for the significace map + + for (UInt component = firstComponent; component <= lastComponent; component++) + { + const UInt contextOffset = getSignificanceMapContextOffset(ComponentID(component)); + + if (firstCtx > 0) + { + for( UInt bin = 0; bin < 2; bin++ ) //always get the DC + { + pcEstBitsSbac->significantBits[ contextOffset ][ bin ] = m_cCUSigSCModel.get( 0, 0, contextOffset ).getEntropyBits( bin ); + } + } + + // This could be made optional, but would require this function to have knowledge of whether the + // TU is transform-skipped or transquant-bypassed and whether the SPS flag is set + for( UInt bin = 0; bin < 2; bin++ ) + { + const Int ctxIdx = significanceMapContextSetStart[chType][CONTEXT_TYPE_SINGLE]; + pcEstBitsSbac->significantBits[ contextOffset + ctxIdx ][ bin ] = m_cCUSigSCModel.get( 0, 0, (contextOffset + ctxIdx) ).getEntropyBits( bin ); + } + + for ( Int ctxIdx = firstCtx; ctxIdx < firstCtx + numCtx; ctxIdx++ ) + { + for( UInt uiBin = 0; uiBin < 2; uiBin++ ) + { + pcEstBitsSbac->significantBits[ contextOffset + ctxIdx ][ uiBin ] = m_cCUSigSCModel.get( 0, 0, (contextOffset + ctxIdx) ).getEntropyBits( uiBin ); + } + } + } + + //-------------------------------------------------------------------------------------------------- +} + + +/*! + **************************************************************************** + * \brief + * estimate bit cost of significant coefficient + **************************************************************************** + */ + +Void TEncSbac::estLastSignificantPositionBit( estBitsSbacStruct* pcEstBitsSbac, Int width, Int height, ChannelType chType ) +{ + //--------------------------------------------------------------------------------------------------. + + //set up the number of channels + + const UInt firstComponent = ((isLuma(chType)) ? (COMPONENT_Y) : (COMPONENT_Cb)); + const UInt lastComponent = ((isLuma(chType)) ? (COMPONENT_Y) : (COMPONENT_Cb)); + + //-------------------------------------------------------------------------------------------------- + + //fill the data for the last-significant-coefficient position + + for (UInt componentIndex = firstComponent; componentIndex <= lastComponent; componentIndex++) + { + const ComponentID component = ComponentID(componentIndex); + + Int iBitsX = 0, iBitsY = 0; + + Int blkSizeOffsetX, blkSizeOffsetY, shiftX, shiftY; + getLastSignificantContextParameters(ComponentID(component), width, height, blkSizeOffsetX, blkSizeOffsetY, shiftX, shiftY); + + Int ctx; + + const ChannelType channelType = toChannelType(ComponentID(component)); + + ContextModel *const pCtxX = m_cCuCtxLastX.get( 0, channelType ); + ContextModel *const pCtxY = m_cCuCtxLastY.get( 0, channelType ); + Int *const lastXBitsArray = pcEstBitsSbac->lastXBits[channelType]; + Int *const lastYBitsArray = pcEstBitsSbac->lastYBits[channelType]; + + //------------------------------------------------ + + //X-coordinate + + for (ctx = 0; ctx < g_uiGroupIdx[ width - 1 ]; ctx++) + { + Int ctxOffset = blkSizeOffsetX + (ctx >>shiftX); + lastXBitsArray[ ctx ] = iBitsX + pCtxX[ ctxOffset ].getEntropyBits( 0 ); + iBitsX += pCtxX[ ctxOffset ].getEntropyBits( 1 ); + } + + lastXBitsArray[ctx] = iBitsX; + + //------------------------------------------------ + + //Y-coordinate + + for (ctx = 0; ctx < g_uiGroupIdx[ height - 1 ]; ctx++) + { + Int ctxOffset = blkSizeOffsetY + (ctx >>shiftY); + lastYBitsArray[ ctx ] = iBitsY + pCtxY[ ctxOffset ].getEntropyBits( 0 ); + iBitsY += pCtxY[ ctxOffset ].getEntropyBits( 1 ); + } + + lastYBitsArray[ctx] = iBitsY; + + } //end of component loop + + //-------------------------------------------------------------------------------------------------- +} + + +/*! + **************************************************************************** + * \brief + * estimate bit cost of significant coefficient + **************************************************************************** + */ +Void TEncSbac::estSignificantCoefficientsBit( estBitsSbacStruct* pcEstBitsSbac, ChannelType chType ) +{ + ContextModel *ctxOne = m_cCUOneSCModel.get(0, 0); + ContextModel *ctxAbs = m_cCUAbsSCModel.get(0, 0); + + const UInt oneStartIndex = ((isLuma(chType)) ? (0) : (NUM_ONE_FLAG_CTX_LUMA)); + const UInt oneStopIndex = ((isLuma(chType)) ? (NUM_ONE_FLAG_CTX_LUMA) : (NUM_ONE_FLAG_CTX)); + const UInt absStartIndex = ((isLuma(chType)) ? (0) : (NUM_ABS_FLAG_CTX_LUMA)); + const UInt absStopIndex = ((isLuma(chType)) ? (NUM_ABS_FLAG_CTX_LUMA) : (NUM_ABS_FLAG_CTX)); + + for (Int ctxIdx = oneStartIndex; ctxIdx < oneStopIndex; ctxIdx++) + { + pcEstBitsSbac->m_greaterOneBits[ ctxIdx ][ 0 ] = ctxOne[ ctxIdx ].getEntropyBits( 0 ); + pcEstBitsSbac->m_greaterOneBits[ ctxIdx ][ 1 ] = ctxOne[ ctxIdx ].getEntropyBits( 1 ); + } + + for (Int ctxIdx = absStartIndex; ctxIdx < absStopIndex; ctxIdx++) + { + pcEstBitsSbac->m_levelAbsBits[ ctxIdx ][ 0 ] = ctxAbs[ ctxIdx ].getEntropyBits( 0 ); + pcEstBitsSbac->m_levelAbsBits[ ctxIdx ][ 1 ] = ctxAbs[ ctxIdx ].getEntropyBits( 1 ); + } +} + +/** + - Initialize our context information from the nominated source. + . + \param pSrc From where to copy context information. + */ +Void TEncSbac::xCopyContextsFrom( const TEncSbac* pSrc ) +{ + memcpy(m_contextModels, pSrc->m_contextModels, m_numContextModels*sizeof(m_contextModels[0])); + memcpy(m_golombRiceAdaptationStatistics, pSrc->m_golombRiceAdaptationStatistics, (sizeof(UInt) * RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS)); +} + +Void TEncSbac::loadContexts ( const TEncSbac* pSrc) +{ + xCopyContextsFrom(pSrc); +} + +/** Performs CABAC encoding of the explicit RDPCM mode + * \param rTu current TU data structure + * \param compID component identifier + */ +Void TEncSbac::codeExplicitRdpcmMode( TComTU &rTu, const ComponentID compID ) +{ + TComDataCU *cu = rTu.getCU(); + const TComRectangle &rect = rTu.getRect(compID); + const UInt absPartIdx = rTu.GetAbsPartIdxTU(compID); + const UInt tuHeight = g_aucConvertToBit[rect.height]; + const UInt tuWidth = g_aucConvertToBit[rect.width]; + + assert(tuHeight == tuWidth); + assert(tuHeight < 4); + + UInt explicitRdpcmMode = cu->getExplicitRdpcmMode(compID, absPartIdx); + + if( explicitRdpcmMode == RDPCM_OFF ) + { + m_pcBinIf->encodeBin (0, m_explicitRdpcmFlagSCModel.get (0, toChannelType(compID), 0)); + } + else if( explicitRdpcmMode == RDPCM_HOR || explicitRdpcmMode == RDPCM_VER ) + { + m_pcBinIf->encodeBin (1, m_explicitRdpcmFlagSCModel.get (0, toChannelType(compID), 0)); + if(explicitRdpcmMode == RDPCM_HOR) + { + m_pcBinIf->encodeBin ( 0, m_explicitRdpcmDirSCModel.get(0, toChannelType(compID), 0)); + } + else + { + m_pcBinIf->encodeBin ( 1, m_explicitRdpcmDirSCModel.get(0, toChannelType(compID), 0)); + } + } + else + { + assert(0); + } +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncSbac.h b/jctvc/TLibEncoder/TEncSbac.h new file mode 100644 index 0000000..fdca32f --- /dev/null +++ b/jctvc/TLibEncoder/TEncSbac.h @@ -0,0 +1,221 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncSbac.h + \brief Context-adaptive entropy encoder class (header) +*/ + +#ifndef __TENCSBAC__ +#define __TENCSBAC__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TLibCommon/TComBitStream.h" +#include "TLibCommon/ContextTables.h" +#include "TLibCommon/ContextModel.h" +#include "TLibCommon/ContextModel3DBuffer.h" +#include "TEncEntropy.h" +#include "TEncBinCoder.h" +#include "TEncBinCoderCABAC.h" +#if FAST_BIT_EST +#include "TEncBinCoderCABACCounter.h" +#endif + +class TEncTop; + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// SBAC encoder class +class TEncSbac : public TEncEntropyIf +{ +public: + TEncSbac(); + virtual ~TEncSbac(); + + Void init ( TEncBinIf* p ) { m_pcBinIf = p; } + Void uninit () { m_pcBinIf = 0; } + + // Virtual list + Void resetEntropy (); + Void determineCabacInitIdx (); + Void setBitstream ( TComBitIf* p ) { m_pcBitIf = p; m_pcBinIf->init( p ); } + Void setSlice ( TComSlice* p ) { m_pcSlice = p; } + + Void load ( const TEncSbac* pSrc ); + Void loadIntraDirMode ( const TEncSbac* pScr, const ChannelType chType ); + Void store ( TEncSbac* pDest ) const; + Void loadContexts ( const TEncSbac* pSrc ); + Void resetBits () { m_pcBinIf->resetBits(); m_pcBitIf->resetBits(); } + UInt getNumberOfWrittenBits () { return m_pcBinIf->getNumWrittenBits(); } + //--SBAC RD + + Void codeVPS ( TComVPS* pcVPS ); + Void codeSPS ( TComSPS* pcSPS ); + Void codePPS ( TComPPS* pcPPS ); + Void codeSliceHeader ( TComSlice* pcSlice ); + Void codeTilesWPPEntryPoint ( TComSlice* pSlice ); + Void codeTerminatingBit ( UInt uilsLast ); + Void codeSliceFinish (); + Void codeSaoMaxUvlc ( UInt code, UInt maxSymbol ); + Void codeSaoMerge ( UInt uiCode ); + Void codeSaoTypeIdx ( UInt uiCode); + Void codeSaoUflc ( UInt uiLength, UInt uiCode ); + Void codeSAOSign ( UInt uiCode); // +#include + + +//! \ingroup TLibEncoder +//! \{ + +static const TComMv s_acMvRefineH[9] = +{ + TComMv( 0, 0 ), // 0 + TComMv( 0, -1 ), // 1 + TComMv( 0, 1 ), // 2 + TComMv( -1, 0 ), // 3 + TComMv( 1, 0 ), // 4 + TComMv( -1, -1 ), // 5 + TComMv( 1, -1 ), // 6 + TComMv( -1, 1 ), // 7 + TComMv( 1, 1 ) // 8 +}; + +static const TComMv s_acMvRefineQ[9] = +{ + TComMv( 0, 0 ), // 0 + TComMv( 0, -1 ), // 1 + TComMv( 0, 1 ), // 2 + TComMv( -1, -1 ), // 5 + TComMv( 1, -1 ), // 6 + TComMv( -1, 0 ), // 3 + TComMv( 1, 0 ), // 4 + TComMv( -1, 1 ), // 7 + TComMv( 1, 1 ) // 8 +}; + +static const UInt s_auiDFilter[9] = +{ + 0, 1, 0, + 2, 3, 2, + 0, 1, 0 +}; + +static Void offsetSubTUCBFs(TComTU &rTu, const ComponentID compID) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(compID); + const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> 1; + + //move the CBFs down a level and set the parent CBF + + UChar subTUCBF[2]; + UChar combinedSubTUCBF = 0; + + for (UInt subTU = 0; subTU < 2; subTU++) + { + const UInt subTUAbsPartIdx = uiAbsPartIdx + (subTU * partIdxesPerSubTU); + + subTUCBF[subTU] = pcCU->getCbf(subTUAbsPartIdx, compID, uiTrDepth); + combinedSubTUCBF |= subTUCBF[subTU]; + } + + for (UInt subTU = 0; subTU < 2; subTU++) + { + const UInt subTUAbsPartIdx = uiAbsPartIdx + (subTU * partIdxesPerSubTU); + const UChar compositeCBF = (subTUCBF[subTU] << 1) | combinedSubTUCBF; + + pcCU->setCbfPartRange((compositeCBF << uiTrDepth), compID, subTUAbsPartIdx, partIdxesPerSubTU); + } +} + + +TEncSearch::TEncSearch() +{ + for (UInt ch=0; chgetQuadtreeTULog2MaxSize()-m_pcEncCfg->getQuadtreeTULog2MinSize()+1; + + for (UInt ch=0; chgetChromaFormatIdc(); + initTempBuff(cform); + + m_pTempPel = new Pel[g_uiMaxCUWidth*g_uiMaxCUHeight]; + + const UInt uiNumLayersToAllocate = pcEncCfg->getQuadtreeTULog2MaxSize()-pcEncCfg->getQuadtreeTULog2MinSize()+1; + const UInt uiNumPartitions = 1<<(g_uiMaxCUDepth<<1); + for (UInt ch=0; ch>(csx+csy) ]; +#if ADAPTIVE_QP_SELECTION + m_ppcQTTempArlCoeff[ch] = new TCoeff*[uiNumLayersToAllocate]; + m_pcQTTempArlCoeff[ch] = new TCoeff [(g_uiMaxCUWidth*g_uiMaxCUHeight)>>(csx+csy) ]; +#endif + m_puhQTTempCbf[ch] = new UChar [uiNumPartitions]; + + for (UInt layer = 0; layer < uiNumLayersToAllocate; layer++) + { + m_ppcQTTempCoeff[ch][layer] = new TCoeff[(g_uiMaxCUWidth*g_uiMaxCUHeight)>>(csx+csy)]; +#if ADAPTIVE_QP_SELECTION + m_ppcQTTempArlCoeff[ch][layer] = new TCoeff[(g_uiMaxCUWidth*g_uiMaxCUHeight)>>(csx+csy) ]; +#endif + } + + m_phQTTempCrossComponentPredictionAlpha[ch] = new Char [uiNumPartitions]; + m_pSharedPredTransformSkip[ch] = new Pel [MAX_CU_SIZE*MAX_CU_SIZE]; + m_pcQTTempTUCoeff[ch] = new TCoeff[MAX_CU_SIZE*MAX_CU_SIZE]; +#if ADAPTIVE_QP_SELECTION + m_ppcQTTempTUArlCoeff[ch] = new TCoeff[MAX_CU_SIZE*MAX_CU_SIZE]; +#endif + m_puhQTTempTransformSkipFlag[ch] = new UChar [uiNumPartitions]; + } + m_puhQTTempTrIdx = new UChar [uiNumPartitions]; + m_pcQTTempTComYuv = new TComYuv[uiNumLayersToAllocate]; + for( UInt ui = 0; ui < uiNumLayersToAllocate; ++ui ) + { + m_pcQTTempTComYuv[ui].create( g_uiMaxCUWidth, g_uiMaxCUHeight, pcEncCfg->getChromaFormatIdc() ); + } + m_pcQTTempTransformSkipTComYuv.create( g_uiMaxCUWidth, g_uiMaxCUHeight, pcEncCfg->getChromaFormatIdc() ); + m_tmpYuvPred.create(MAX_CU_SIZE, MAX_CU_SIZE, pcEncCfg->getChromaFormatIdc()); +} + +#if FASTME_SMOOTHER_MV +#define FIRSTSEARCHSTOP 1 +#else +#define FIRSTSEARCHSTOP 0 +#endif + +#define TZ_SEARCH_CONFIGURATION \ +const Int iRaster = 5; /* TZ soll von aussen ?ergeben werden */ \ +const Bool bTestOtherPredictedMV = 0; \ +const Bool bTestZeroVector = 1; \ +const Bool bTestZeroVectorStart = 0; \ +const Bool bTestZeroVectorStop = 0; \ +const Bool bFirstSearchDiamond = 1; /* 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch */ \ +const Bool bFirstSearchStop = FIRSTSEARCHSTOP; \ +const UInt uiFirstSearchRounds = 3; /* first search stop X rounds after best match (must be >=1) */ \ +const Bool bEnableRasterSearch = 1; \ +const Bool bAlwaysRasterSearch = 0; /* ===== 1: BETTER but factor 2 slower ===== */ \ +const Bool bRasterRefinementEnable = 0; /* enable either raster refinement or star refinement */ \ +const Bool bRasterRefinementDiamond = 0; /* 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch */ \ +const Bool bStarRefinementEnable = 1; /* enable either star refinement or raster refinement */ \ +const Bool bStarRefinementDiamond = 1; /* 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch */ \ +const Bool bStarRefinementStop = 0; \ +const UInt uiStarRefinementRounds = 2; /* star refinement stop X rounds after best match (must be >=1) */ \ + + +#define SEL_SEARCH_CONFIGURATION \ + const Bool bTestOtherPredictedMV = 1; \ + const Bool bTestZeroVector = 1; \ + const Bool bEnableRasterSearch = 1; \ + const Bool bAlwaysRasterSearch = 0; /* ===== 1: BETTER but factor 15x slower ===== */ \ + const Bool bStarRefinementEnable = 1; /* enable either star refinement or raster refinement */ \ + const Bool bStarRefinementDiamond = 1; /* 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch */ \ + const Bool bStarRefinementStop = 0; \ + const UInt uiStarRefinementRounds = 2; /* star refinement stop X rounds after best match (must be >=1) */ \ + const UInt uiSearchRange = m_iSearchRange; \ + const Int uiSearchRangeInitial = m_iSearchRange >> 2; \ + const Int uiSearchStep = 4; \ + const Int iMVDistThresh = 8; \ + + + +__inline Void TEncSearch::xTZSearchHelp( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, const Int iSearchX, const Int iSearchY, const UChar ucPointNr, const UInt uiDistance ) +{ + Distortion uiSad = 0; + + Pel* piRefSrch; + + piRefSrch = rcStruct.piRefY + iSearchY * rcStruct.iYStride + iSearchX; + + //-- jclee for using the SAD function pointer + m_pcRdCost->setDistParam( pcPatternKey, piRefSrch, rcStruct.iYStride, m_cDistParam ); + + if(m_pcEncCfg->getFastSearch() != SELECTIVE) + { + // fast encoder decision: use subsampled SAD when rows > 8 for integer ME + if ( m_pcEncCfg->getUseFastEnc() ) + { + if ( m_cDistParam.iRows > 8 ) + { + m_cDistParam.iSubShift = 1; + } + } + } + + setDistParamComp(COMPONENT_Y); + + // distortion + m_cDistParam.bitDepth = g_bitDepth[CHANNEL_TYPE_LUMA]; + if(m_pcEncCfg->getFastSearch() == SELECTIVE) + { + Int isubShift = 0; + // motion cost + UInt uiBitCost = m_pcRdCost->getCost( iSearchX, iSearchY ); + + if ( m_cDistParam.iRows > 32 ) + m_cDistParam.iSubShift = 4; + else if ( m_cDistParam.iRows > 16 ) + m_cDistParam.iSubShift = 3; + else if ( m_cDistParam.iRows > 8 ) + m_cDistParam.iSubShift = 2; + else + m_cDistParam.iSubShift = 1; + + Distortion uiTempSad = m_cDistParam.DistFunc( &m_cDistParam ); + if((uiTempSad + uiBitCost) < rcStruct.uiBestSad) + { + uiSad += uiTempSad >> m_cDistParam.iSubShift; + while(m_cDistParam.iSubShift > 0) + { + isubShift = m_cDistParam.iSubShift -1; + m_cDistParam.pOrg = pcPatternKey->getROIY() + (pcPatternKey->getPatternLStride() << isubShift); + m_cDistParam.pCur = piRefSrch + (rcStruct.iYStride << isubShift); + uiTempSad = m_cDistParam.DistFunc( &m_cDistParam ); + uiSad += uiTempSad >> m_cDistParam.iSubShift; + if(((uiSad << isubShift) + uiBitCost) > rcStruct.uiBestSad) + break; + + m_cDistParam.iSubShift--; + } + + if(m_cDistParam.iSubShift == 0) + { + uiSad += uiBitCost; + if( uiSad < rcStruct.uiBestSad ) + { + rcStruct.uiBestSad = uiSad; + rcStruct.iBestX = iSearchX; + rcStruct.iBestY = iSearchY; + rcStruct.uiBestDistance = uiDistance; + rcStruct.uiBestRound = 0; + rcStruct.ucPointNr = ucPointNr; + } + } + } + } + else + { + uiSad = m_cDistParam.DistFunc( &m_cDistParam ); + + // motion cost + uiSad += m_pcRdCost->getCost( iSearchX, iSearchY ); + + if( uiSad < rcStruct.uiBestSad ) + { + rcStruct.uiBestSad = uiSad; + rcStruct.iBestX = iSearchX; + rcStruct.iBestY = iSearchY; + rcStruct.uiBestDistance = uiDistance; + rcStruct.uiBestRound = 0; + rcStruct.ucPointNr = ucPointNr; + } + } +} + + + + +__inline Void TEncSearch::xTZ2PointSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB ) +{ + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + + // 2 point search, // 1 2 3 + // check only the 2 untested points // 4 0 5 + // around the start point // 6 7 8 + Int iStartX = rcStruct.iBestX; + Int iStartY = rcStruct.iBestY; + switch( rcStruct.ucPointNr ) + { + case 1: + { + if ( (iStartX - 1) >= iSrchRngHorLeft ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY, 0, 2 ); + } + if ( (iStartY - 1) >= iSrchRngVerTop ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY - 1, 0, 2 ); + } + } + break; + case 2: + { + if ( (iStartY - 1) >= iSrchRngVerTop ) + { + if ( (iStartX - 1) >= iSrchRngHorLeft ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY - 1, 0, 2 ); + } + if ( (iStartX + 1) <= iSrchRngHorRight ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY - 1, 0, 2 ); + } + } + } + break; + case 3: + { + if ( (iStartY - 1) >= iSrchRngVerTop ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY - 1, 0, 2 ); + } + if ( (iStartX + 1) <= iSrchRngHorRight ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY, 0, 2 ); + } + } + break; + case 4: + { + if ( (iStartX - 1) >= iSrchRngHorLeft ) + { + if ( (iStartY + 1) <= iSrchRngVerBottom ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY + 1, 0, 2 ); + } + if ( (iStartY - 1) >= iSrchRngVerTop ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY - 1, 0, 2 ); + } + } + } + break; + case 5: + { + if ( (iStartX + 1) <= iSrchRngHorRight ) + { + if ( (iStartY - 1) >= iSrchRngVerTop ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY - 1, 0, 2 ); + } + if ( (iStartY + 1) <= iSrchRngVerBottom ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY + 1, 0, 2 ); + } + } + } + break; + case 6: + { + if ( (iStartX - 1) >= iSrchRngHorLeft ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY , 0, 2 ); + } + if ( (iStartY + 1) <= iSrchRngVerBottom ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY + 1, 0, 2 ); + } + } + break; + case 7: + { + if ( (iStartY + 1) <= iSrchRngVerBottom ) + { + if ( (iStartX - 1) >= iSrchRngHorLeft ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY + 1, 0, 2 ); + } + if ( (iStartX + 1) <= iSrchRngHorRight ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY + 1, 0, 2 ); + } + } + } + break; + case 8: + { + if ( (iStartX + 1) <= iSrchRngHorRight ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY, 0, 2 ); + } + if ( (iStartY + 1) <= iSrchRngVerBottom ) + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY + 1, 0, 2 ); + } + } + break; + default: + { + assert( false ); + } + break; + } // switch( rcStruct.ucPointNr ) +} + + + + +__inline Void TEncSearch::xTZ8PointSquareSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, const Int iStartX, const Int iStartY, const Int iDist ) +{ + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + + // 8 point search, // 1 2 3 + // search around the start point // 4 0 5 + // with the required distance // 6 7 8 + assert( iDist != 0 ); + const Int iTop = iStartY - iDist; + const Int iBottom = iStartY + iDist; + const Int iLeft = iStartX - iDist; + const Int iRight = iStartX + iDist; + rcStruct.uiBestRound += 1; + + if ( iTop >= iSrchRngVerTop ) // check top + { + if ( iLeft >= iSrchRngHorLeft ) // check top left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iTop, 1, iDist ); + } + // top middle + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist ); + + if ( iRight <= iSrchRngHorRight ) // check top right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iTop, 3, iDist ); + } + } // check top + if ( iLeft >= iSrchRngHorLeft ) // check middle left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist ); + } + if ( iRight <= iSrchRngHorRight ) // check middle right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist ); + } + if ( iBottom <= iSrchRngVerBottom ) // check bottom + { + if ( iLeft >= iSrchRngHorLeft ) // check bottom left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iBottom, 6, iDist ); + } + // check bottom middle + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist ); + + if ( iRight <= iSrchRngHorRight ) // check bottom right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iBottom, 8, iDist ); + } + } // check bottom +} + + + + +__inline Void TEncSearch::xTZ8PointDiamondSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, const Int iStartX, const Int iStartY, const Int iDist ) +{ + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + + // 8 point search, // 1 2 3 + // search around the start point // 4 0 5 + // with the required distance // 6 7 8 + assert ( iDist != 0 ); + const Int iTop = iStartY - iDist; + const Int iBottom = iStartY + iDist; + const Int iLeft = iStartX - iDist; + const Int iRight = iStartX + iDist; + rcStruct.uiBestRound += 1; + + if ( iDist == 1 ) // iDist == 1 + { + if ( iTop >= iSrchRngVerTop ) // check top + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist ); + } + if ( iLeft >= iSrchRngHorLeft ) // check middle left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist ); + } + if ( iRight <= iSrchRngHorRight ) // check middle right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist ); + } + if ( iBottom <= iSrchRngVerBottom ) // check bottom + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist ); + } + } + else // if (iDist != 1) + { + if ( iDist <= 8 ) + { + const Int iTop_2 = iStartY - (iDist>>1); + const Int iBottom_2 = iStartY + (iDist>>1); + const Int iLeft_2 = iStartX - (iDist>>1); + const Int iRight_2 = iStartX + (iDist>>1); + + if ( iTop >= iSrchRngVerTop && iLeft >= iSrchRngHorLeft && + iRight <= iSrchRngHorRight && iBottom <= iSrchRngVerBottom ) // check border + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iTop_2, 1, iDist>>1 ); + xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iTop_2, 3, iDist>>1 ); + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iBottom_2, 6, iDist>>1 ); + xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iBottom_2, 8, iDist>>1 ); + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist ); + } + else // check border + { + if ( iTop >= iSrchRngVerTop ) // check top + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist ); + } + if ( iTop_2 >= iSrchRngVerTop ) // check half top + { + if ( iLeft_2 >= iSrchRngHorLeft ) // check half left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iTop_2, 1, (iDist>>1) ); + } + if ( iRight_2 <= iSrchRngHorRight ) // check half right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iTop_2, 3, (iDist>>1) ); + } + } // check half top + if ( iLeft >= iSrchRngHorLeft ) // check left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist ); + } + if ( iRight <= iSrchRngHorRight ) // check right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist ); + } + if ( iBottom_2 <= iSrchRngVerBottom ) // check half bottom + { + if ( iLeft_2 >= iSrchRngHorLeft ) // check half left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iBottom_2, 6, (iDist>>1) ); + } + if ( iRight_2 <= iSrchRngHorRight ) // check half right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iBottom_2, 8, (iDist>>1) ); + } + } // check half bottom + if ( iBottom <= iSrchRngVerBottom ) // check bottom + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist ); + } + } // check border + } + else // iDist > 8 + { + if ( iTop >= iSrchRngVerTop && iLeft >= iSrchRngHorLeft && + iRight <= iSrchRngHorRight && iBottom <= iSrchRngVerBottom ) // check border + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 0, iDist ); + for ( Int index = 1; index < 4; index++ ) + { + Int iPosYT = iTop + ((iDist>>2) * index); + Int iPosYB = iBottom - ((iDist>>2) * index); + Int iPosXL = iStartX - ((iDist>>2) * index); + Int iPosXR = iStartX + ((iDist>>2) * index); + xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYT, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYT, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYB, 0, iDist ); + xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYB, 0, iDist ); + } + } + else // check border + { + if ( iTop >= iSrchRngVerTop ) // check top + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 0, iDist ); + } + if ( iLeft >= iSrchRngHorLeft ) // check left + { + xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 0, iDist ); + } + if ( iRight <= iSrchRngHorRight ) // check right + { + xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 0, iDist ); + } + if ( iBottom <= iSrchRngVerBottom ) // check bottom + { + xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 0, iDist ); + } + for ( Int index = 1; index < 4; index++ ) + { + Int iPosYT = iTop + ((iDist>>2) * index); + Int iPosYB = iBottom - ((iDist>>2) * index); + Int iPosXL = iStartX - ((iDist>>2) * index); + Int iPosXR = iStartX + ((iDist>>2) * index); + + if ( iPosYT >= iSrchRngVerTop ) // check top + { + if ( iPosXL >= iSrchRngHorLeft ) // check left + { + xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYT, 0, iDist ); + } + if ( iPosXR <= iSrchRngHorRight ) // check right + { + xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYT, 0, iDist ); + } + } // check top + if ( iPosYB <= iSrchRngVerBottom ) // check bottom + { + if ( iPosXL >= iSrchRngHorLeft ) // check left + { + xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYB, 0, iDist ); + } + if ( iPosXR <= iSrchRngHorRight ) // check right + { + xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYB, 0, iDist ); + } + } // check bottom + } // for ... + } // check border + } // iDist <= 8 + } // iDist == 1 +} + + + + + +//<-- + +Distortion TEncSearch::xPatternRefinement( TComPattern* pcPatternKey, + TComMv baseRefMv, + Int iFrac, TComMv& rcMvFrac, + Bool bAllowUseOfHadamard + ) +{ + Distortion uiDist; + Distortion uiDistBest = std::numeric_limits::max(); + UInt uiDirecBest = 0; + + Pel* piRefPos; + Int iRefStride = m_filteredBlock[0][0].getStride(COMPONENT_Y); + + m_pcRdCost->setDistParam( pcPatternKey, m_filteredBlock[0][0].getAddr(COMPONENT_Y), iRefStride, 1, m_cDistParam, m_pcEncCfg->getUseHADME() && bAllowUseOfHadamard ); + + const TComMv* pcMvRefine = (iFrac == 2 ? s_acMvRefineH : s_acMvRefineQ); + + for (UInt i = 0; i < 9; i++) + { + TComMv cMvTest = pcMvRefine[i]; + cMvTest += baseRefMv; + + Int horVal = cMvTest.getHor() * iFrac; + Int verVal = cMvTest.getVer() * iFrac; + piRefPos = m_filteredBlock[ verVal & 3 ][ horVal & 3 ].getAddr(COMPONENT_Y); + if ( horVal == 2 && ( verVal & 1 ) == 0 ) + { + piRefPos += 1; + } + if ( ( horVal & 1 ) == 0 && verVal == 2 ) + { + piRefPos += iRefStride; + } + cMvTest = pcMvRefine[i]; + cMvTest += rcMvFrac; + + setDistParamComp(COMPONENT_Y); + + m_cDistParam.pCur = piRefPos; + m_cDistParam.bitDepth = g_bitDepth[CHANNEL_TYPE_LUMA]; + uiDist = m_cDistParam.DistFunc( &m_cDistParam ); + uiDist += m_pcRdCost->getCost( cMvTest.getHor(), cMvTest.getVer() ); + + if ( uiDist < uiDistBest ) + { + uiDistBest = uiDist; + uiDirecBest = i; + } + } + + rcMvFrac = pcMvRefine[uiDirecBest]; + + return uiDistBest; +} + + + +Void +TEncSearch::xEncSubdivCbfQT(TComTU &rTu, + Bool bLuma, + Bool bChroma ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + const UInt uiSubdiv = ( uiTrMode > uiTrDepth ? 1 : 0 ); + const UInt uiLog2LumaTrafoSize = rTu.GetLog2LumaTrSize(); + + if( pcCU->isIntra(0) && pcCU->getPartitionSize(0) == SIZE_NxN && uiTrDepth == 0 ) + { + assert( uiSubdiv ); + } + else if( uiLog2LumaTrafoSize > pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() ) + { + assert( uiSubdiv ); + } + else if( uiLog2LumaTrafoSize == pcCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) + { + assert( !uiSubdiv ); + } + else if( uiLog2LumaTrafoSize == pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) + { + assert( !uiSubdiv ); + } + else + { + assert( uiLog2LumaTrafoSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ); + if( bLuma ) + { + m_pcEntropyCoder->encodeTransformSubdivFlag( uiSubdiv, 5 - uiLog2LumaTrafoSize ); + } + } + + if ( bChroma ) + { + const UInt numberValidComponents = getNumberValidComponents(rTu.GetChromaFormat()); + for (UInt ch=COMPONENT_Cb; chgetCbf( uiAbsPartIdx, compID, uiTrDepth-1 ) )) + m_pcEntropyCoder->encodeQtCbf(rTu, compID, (uiSubdiv == 0)); + } + } + + if( uiSubdiv ) + { + TComTURecurse tuRecurse(rTu, false); + do + { + xEncSubdivCbfQT( tuRecurse, bLuma, bChroma ); + } while (tuRecurse.nextSection(rTu)); + } + else + { + //===== Cbfs ===== + if( bLuma ) + { + m_pcEntropyCoder->encodeQtCbf( rTu, COMPONENT_Y, true ); + } + } +} + + + + +Void +TEncSearch::xEncCoeffQT(TComTU &rTu, + const ComponentID component, + Bool bRealCoeff ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrDepth=rTu.GetTransformDepthRel(); + + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + const UInt uiSubdiv = ( uiTrMode > uiTrDepth ? 1 : 0 ); + + if( uiSubdiv ) + { + TComTURecurse tuRecurseChild(rTu, false); + do + { + xEncCoeffQT( tuRecurseChild, component, bRealCoeff ); + } while (tuRecurseChild.nextSection(rTu) ); + } + else if (rTu.ProcessComponentSection(component)) + { + //===== coefficients ===== + const UInt uiLog2TrafoSize = rTu.GetLog2LumaTrSize(); + UInt uiCoeffOffset = rTu.getCoefficientOffset(component); + UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrafoSize; + TCoeff* pcCoeff = bRealCoeff ? pcCU->getCoeff(component) : m_ppcQTTempCoeff[component][uiQTLayer]; + + if (isChroma(component) && (pcCU->getCbf( rTu.GetAbsPartIdxTU(), COMPONENT_Y, uiTrMode ) != 0) && pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction() ) + { + m_pcEntropyCoder->encodeCrossComponentPrediction( rTu, component ); + } + + m_pcEntropyCoder->encodeCoeffNxN( rTu, pcCoeff+uiCoeffOffset, component ); + } +} + + + + +Void +TEncSearch::xEncIntraHeader( TComDataCU* pcCU, + UInt uiTrDepth, + UInt uiAbsPartIdx, + Bool bLuma, + Bool bChroma ) +{ + if( bLuma ) + { + // CU header + if( uiAbsPartIdx == 0 ) + { + if( !pcCU->getSlice()->isIntra() ) + { + if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag( pcCU, 0, true ); + } + m_pcEntropyCoder->encodeSkipFlag( pcCU, 0, true ); + m_pcEntropyCoder->encodePredMode( pcCU, 0, true ); + } + m_pcEntropyCoder ->encodePartSize( pcCU, 0, pcCU->getDepth(0), true ); + + if (pcCU->isIntra(0) && pcCU->getPartitionSize(0) == SIZE_2Nx2N ) + { + m_pcEntropyCoder->encodeIPCMInfo( pcCU, 0, true ); + + if ( pcCU->getIPCMFlag (0)) + { + return; + } + } + } + // luma prediction mode + if( pcCU->getPartitionSize(0) == SIZE_2Nx2N ) + { + if (uiAbsPartIdx==0) + { + m_pcEntropyCoder->encodeIntraDirModeLuma ( pcCU, 0 ); + } + } + else + { + UInt uiQNumParts = pcCU->getTotalNumPart() >> 2; + if (uiTrDepth>0 && (uiAbsPartIdx%uiQNumParts)==0) m_pcEntropyCoder->encodeIntraDirModeLuma ( pcCU, uiAbsPartIdx ); + } + } + + if( bChroma ) + { + if( pcCU->getPartitionSize(0) == SIZE_2Nx2N || !enable4ChromaPUsInIntraNxNCU(pcCU->getPic()->getChromaFormat())) + { + if(uiAbsPartIdx==0) + { + m_pcEntropyCoder->encodeIntraDirModeChroma ( pcCU, uiAbsPartIdx ); + } + } + else + { + UInt uiQNumParts = pcCU->getTotalNumPart() >> 2; + assert(uiTrDepth>0); + if ((uiAbsPartIdx%uiQNumParts)==0) + { + m_pcEntropyCoder->encodeIntraDirModeChroma ( pcCU, uiAbsPartIdx ); + } + } + } +} + + + + +UInt +TEncSearch::xGetIntraBitsQT(TComTU &rTu, + Bool bLuma, + Bool bChroma, + Bool bRealCoeff /* just for test */ ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrDepth=rTu.GetTransformDepthRel(); + m_pcEntropyCoder->resetBits(); + xEncIntraHeader ( pcCU, uiTrDepth, uiAbsPartIdx, bLuma, bChroma ); + xEncSubdivCbfQT ( rTu, bLuma, bChroma ); + + if( bLuma ) + { + xEncCoeffQT ( rTu, COMPONENT_Y, bRealCoeff ); + } + if( bChroma ) + { + xEncCoeffQT ( rTu, COMPONENT_Cb, bRealCoeff ); + xEncCoeffQT ( rTu, COMPONENT_Cr, bRealCoeff ); + } + UInt uiBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + + return uiBits; +} + +UInt TEncSearch::xGetIntraBitsQTChroma(TComTU &rTu, + ComponentID compID, + Bool bRealCoeff /* just for test */ ) +{ + m_pcEntropyCoder->resetBits(); + xEncCoeffQT ( rTu, compID, bRealCoeff ); + UInt uiBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + return uiBits; +} + +Void TEncSearch::xIntraCodingTUBlock( TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + const Bool checkCrossCPrediction, + Distortion& ruiDist, + const ComponentID compID, + TComTU& rTu + DEBUG_STRING_FN_DECLARE(sDebug) + ,Int default0Save1Load2 + ) +{ + if (!rTu.ProcessComponentSection(compID)) return; + const Bool bIsLuma = isLuma(compID); + const TComRectangle &rect= rTu.getRect(compID); + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + + const UInt uiTrDepth=rTu.GetTransformDepthRelAdj(compID); + const UInt uiFullDepth = rTu.GetTransformDepthTotal(); + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + const ChromaFormat chFmt = pcOrgYuv->getChromaFormat(); + const ChannelType chType = toChannelType(compID); + + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + const UInt uiStride = pcOrgYuv ->getStride (compID); + Pel* piOrg = pcOrgYuv ->getAddr( compID, uiAbsPartIdx ); + Pel* piPred = pcPredYuv->getAddr( compID, uiAbsPartIdx ); + Pel* piResi = pcResiYuv->getAddr( compID, uiAbsPartIdx ); + Pel* piReco = pcPredYuv->getAddr( compID, uiAbsPartIdx ); + const UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + Pel* piRecQt = m_pcQTTempTComYuv[ uiQTLayer ].getAddr( compID, uiAbsPartIdx ); + const UInt uiRecQtStride = m_pcQTTempTComYuv[ uiQTLayer ].getStride(compID); + const UInt uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx; + Pel* piRecIPred = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder ); + UInt uiRecIPredStride = pcCU->getPic()->getPicYuvRec()->getStride ( compID ); + TCoeff* pcCoeff = m_ppcQTTempCoeff[compID][uiQTLayer] + rTu.getCoefficientOffset(compID); + Bool useTransformSkip = pcCU->getTransformSkip(uiAbsPartIdx, compID); + +#if ADAPTIVE_QP_SELECTION + TCoeff* pcArlCoeff = m_ppcQTTempArlCoeff[compID][ uiQTLayer ] + rTu.getCoefficientOffset(compID); +#endif + + const UInt uiChPredMode = pcCU->getIntraDir( chType, uiAbsPartIdx ); + const UInt uiChCodedMode = (uiChPredMode==DM_CHROMA_IDX && !bIsLuma) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, chFmt)) : uiChPredMode; + const UInt uiChFinalMode = ((chFmt == CHROMA_422) && !bIsLuma) ? g_chroma422IntraAngleMappingTable[uiChCodedMode] : uiChCodedMode; + + const Int blkX = g_auiRasterToPelX[ g_auiZscanToRaster[ uiAbsPartIdx ] ]; + const Int blkY = g_auiRasterToPelY[ g_auiZscanToRaster[ uiAbsPartIdx ] ]; + const Int bufferOffset = blkX + (blkY * MAX_CU_SIZE); + Pel *const encoderLumaResidual = resiLuma[RESIDUAL_ENCODER_SIDE ] + bufferOffset; + Pel *const reconstructedLumaResidual = resiLuma[RESIDUAL_RECONSTRUCTED] + bufferOffset; + const Bool bUseCrossCPrediction = isChroma(compID) && (uiChPredMode == DM_CHROMA_IDX) && checkCrossCPrediction; + const Bool bUseReconstructedResidualForEstimate = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); + Pel *const lumaResidualForEstimate = bUseReconstructedResidualForEstimate ? reconstructedLumaResidual : encoderLumaResidual; + +#ifdef DEBUG_STRING + const Int debugPredModeMask=DebugStringGetPredModeMask(MODE_INTRA); +#endif + + //===== init availability pattern ===== + Bool bAboveAvail = false; + Bool bLeftAvail = false; + + DEBUG_STRING_NEW(sTemp) + +#ifndef DEBUG_STRING + if( default0Save1Load2 != 2 ) +#endif + { + const Bool bUseFilteredPredictions=TComPrediction::filteringIntraReferenceSamples(compID, uiChFinalMode, uiWidth, uiHeight, chFmt, pcCU->getSlice()->getSPS()->getDisableIntraReferenceSmoothing()); + + initAdiPatternChType( rTu, bAboveAvail, bLeftAvail, compID, bUseFilteredPredictions DEBUG_STRING_PASS_INTO(sDebug) ); + + //===== get prediction signal ===== + predIntraAng( compID, uiChFinalMode, piOrg, uiStride, piPred, uiStride, rTu, bAboveAvail, bLeftAvail, bUseFilteredPredictions ); + + // save prediction + if( default0Save1Load2 == 1 ) + { + Pel* pPred = piPred; + Pel* pPredBuf = m_pSharedPredTransformSkip[compID]; + Int k = 0; + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pPredBuf[ k ++ ] = pPred[ uiX ]; + } + pPred += uiStride; + } + } + } +#ifndef DEBUG_STRING + else + { + // load prediction + Pel* pPred = piPred; + Pel* pPredBuf = m_pSharedPredTransformSkip[compID]; + Int k = 0; + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pPred[ uiX ] = pPredBuf[ k ++ ]; + } + pPred += uiStride; + } + } +#endif + + //===== get residual signal ===== + { + // get residual + Pel* pOrg = piOrg; + Pel* pPred = piPred; + Pel* pResi = piResi; + + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pResi[ uiX ] = pOrg[ uiX ] - pPred[ uiX ]; + } + + pOrg += uiStride; + pResi += uiStride; + pPred += uiStride; + } + } + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + if (bUseCrossCPrediction) + { + if (xCalcCrossComponentPredictionAlpha( rTu, compID, lumaResidualForEstimate, piResi, uiWidth, uiHeight, MAX_CU_SIZE, uiStride ) == 0) return; + TComTrQuant::crossComponentPrediction ( rTu, compID, reconstructedLumaResidual, piResi, piResi, uiWidth, uiHeight, MAX_CU_SIZE, uiStride, uiStride, false ); + } + else if (isLuma(compID) && !bUseReconstructedResidualForEstimate) + { + xStoreCrossComponentPredictionResult( encoderLumaResidual, piResi, rTu, 0, 0, MAX_CU_SIZE, uiStride ); + } + } + + //===== transform and quantization ===== + //--- init rate estimation arrays for RDOQ --- + if( useTransformSkip ? m_pcEncCfg->getUseRDOQTS() : m_pcEncCfg->getUseRDOQ() ) + { + m_pcEntropyCoder->estimateBit( m_pcTrQuant->m_pcEstBitsSbac, uiWidth, uiHeight, chType ); + } + + //--- transform and quantization --- + TCoeff uiAbsSum = 0; + if (bIsLuma) + { + pcCU ->setTrIdxSubParts ( uiTrDepth, uiAbsPartIdx, uiFullDepth ); + } + + const QpParam cQP(*pcCU, compID); + +#if RDOQ_CHROMA_LAMBDA + m_pcTrQuant->selectLambda (compID); +#endif + + m_pcTrQuant->transformNxN ( rTu, compID, piResi, uiStride, pcCoeff, +#if ADAPTIVE_QP_SELECTION + pcArlCoeff, +#endif + uiAbsSum, cQP + ); + + //--- inverse transform --- + +#ifdef DEBUG_STRING + if ( (uiAbsSum > 0) || (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask) ) +#else + if ( uiAbsSum > 0 ) +#endif + { + m_pcTrQuant->invTransformNxN ( rTu, compID, piResi, uiStride, pcCoeff, cQP DEBUG_STRING_PASS_INTO_OPTIONAL(&sDebug, (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask)) ); + } + else + { + Pel* pResi = piResi; + memset( pcCoeff, 0, sizeof( TCoeff ) * uiWidth * uiHeight ); + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + memset( pResi, 0, sizeof( Pel ) * uiWidth ); + pResi += uiStride; + } + } + + + //===== reconstruction ===== + { + Pel* pPred = piPred; + Pel* pResi = piResi; + Pel* pReco = piReco; + Pel* pRecQt = piRecQt; + Pel* pRecIPred = piRecIPred; + const UInt clipbd=g_bitDepth[chType]; + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + if (bUseCrossCPrediction) + { + TComTrQuant::crossComponentPrediction( rTu, compID, reconstructedLumaResidual, piResi, piResi, uiWidth, uiHeight, MAX_CU_SIZE, uiStride, uiStride, true ); + } + else if (isLuma(compID)) + { + xStoreCrossComponentPredictionResult( reconstructedLumaResidual, piResi, rTu, 0, 0, MAX_CU_SIZE, uiStride ); + } + } + + #ifdef DEBUG_STRING + std::stringstream ss(stringstream::out); + const Bool bDebugPred=((DebugOptionList::DebugString_Pred.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID)); + const Bool bDebugResi=((DebugOptionList::DebugString_Resi.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID)); + const Bool bDebugReco=((DebugOptionList::DebugString_Reco.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID)); + + if (bDebugPred || bDebugResi || bDebugReco) + { + ss << "###: " << "CompID: " << compID << " pred mode (ch/fin): " << uiChPredMode << "/" << uiChFinalMode << " absPartIdx: " << rTu.GetAbsPartIdxTU() << "\n"; + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + ss << "###: "; + if (bDebugPred) + { + ss << " - pred: "; + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + ss << pPred[ uiX ] << ", "; + } + } + if (bDebugResi) ss << " - resi: "; + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + if (bDebugResi) ss << pResi[ uiX ] << ", "; + pReco [ uiX ] = Pel(ClipBD( Int(pPred[uiX]) + Int(pResi[uiX]), clipbd )); + pRecQt [ uiX ] = pReco[ uiX ]; + pRecIPred[ uiX ] = pReco[ uiX ]; + } + if (bDebugReco) + { + ss << " - reco: "; + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + ss << pReco[ uiX ] << ", "; + } + } + pPred += uiStride; + pResi += uiStride; + pReco += uiStride; + pRecQt += uiRecQtStride; + pRecIPred += uiRecIPredStride; + ss << "\n"; + } + DEBUG_STRING_APPEND(sDebug, ss.str()) + } + else +#endif + { + + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pReco [ uiX ] = Pel(ClipBD( Int(pPred[uiX]) + Int(pResi[uiX]), clipbd )); + pRecQt [ uiX ] = pReco[ uiX ]; + pRecIPred[ uiX ] = pReco[ uiX ]; + } + pPred += uiStride; + pResi += uiStride; + pReco += uiStride; + pRecQt += uiRecQtStride; + pRecIPred += uiRecIPredStride; + } + } + } + + //===== update distortion ===== + ruiDist += m_pcRdCost->getDistPart( g_bitDepth[chType], piReco, uiStride, piOrg, uiStride, uiWidth, uiHeight, compID ); +} + + + + + +Void +TEncSearch::xRecurIntraCodingQT(Bool bLumaOnly, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion& ruiDistY, + Distortion& ruiDistC, +#if HHI_RQT_INTRA_SPEEDUP + Bool bCheckFirst, +#endif + Double& dRDCost, + TComTU& rTu + DEBUG_STRING_FN_DECLARE(sDebug)) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiFullDepth = rTu.GetTransformDepthTotal(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + Bool bCheckFull = ( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() ); + Bool bCheckSplit = ( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ); + const UInt numValidComp = (bLumaOnly) ? 1 : pcOrgYuv->getNumberValidComponents(); + + Pel resiLumaSplit [NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]; + Pel resiLumaSingle[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]; + + Bool bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES]; + for (UInt residualTypeIndex = 0; residualTypeIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; residualTypeIndex++) + { + bMaintainResidual[residualTypeIndex] = true; //assume true unless specified otherwise + } + + bMaintainResidual[RESIDUAL_ENCODER_SIDE] = !(m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate()); + +#if HHI_RQT_INTRA_SPEEDUP + Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize(); + Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE); + // don't check split if TU size is less or equal to max TU size + Bool noSplitIntraMaxTuSize = bCheckFull; + if(m_pcEncCfg->getRDpenalty() && ! isIntraSlice) + { + // in addition don't check split if TU size is less or equal to 16x16 TU size for non-intra slice + noSplitIntraMaxTuSize = ( uiLog2TrSize <= min(maxTuSize,4) ); + + // if maximum RD-penalty don't check TU size 32x32 + if(m_pcEncCfg->getRDpenalty()==2) + { + bCheckFull = ( uiLog2TrSize <= min(maxTuSize,4)); + } + } + if( bCheckFirst && noSplitIntraMaxTuSize ) + + { + bCheckSplit = false; + } +#else + Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize(); + Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE); + // if maximum RD-penalty don't check TU size 32x32 + if((m_pcEncCfg->getRDpenalty()==2) && !isIntraSlice) + { + bCheckFull = ( uiLog2TrSize <= min(maxTuSize,4)); + } +#endif + Double dSingleCost = MAX_DOUBLE; + Distortion uiSingleDist[MAX_NUM_CHANNEL_TYPE] = {0,0}; + UInt uiSingleCbf[MAX_NUM_COMPONENT] = {0,0,0}; + Bool checkTransformSkip = pcCU->getSlice()->getPPS()->getUseTransformSkip(); + Int bestModeId[MAX_NUM_COMPONENT] = { 0, 0, 0}; + checkTransformSkip &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getTransformSkipLog2MaxSize()); + checkTransformSkip &= (!pcCU->getCUTransquantBypass(0)); + + if ( m_pcEncCfg->getUseTransformSkipFast() ) + { + checkTransformSkip &= (pcCU->getPartitionSize(uiAbsPartIdx)==SIZE_NxN); + } + + if( bCheckFull ) + { + if(checkTransformSkip == true) + { + //----- store original entropy coding status ----- + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + + Distortion singleDistTmp[MAX_NUM_CHANNEL_TYPE] = { 0, 0 }; + UInt singleCbfTmp[MAX_NUM_COMPONENT] = { 0, 0, 0 }; + Double singleCostTmp = 0; + Int firstCheckId = 0; + + for(Int modeId = firstCheckId; modeId < 2; modeId ++) + { + DEBUG_STRING_NEW(sModeString) + Int default0Save1Load2 = 0; + singleDistTmp[0]=singleDistTmp[1]=0; + if(modeId == firstCheckId) + { + default0Save1Load2 = 1; + } + else + { + default0Save1Load2 = 2; + } + + for(UInt ch=COMPONENT_Y; chsetTransformSkipSubParts ( modeId, compID, uiAbsPartIdx, totalAdjustedDepthChan ); + + xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaSingle, false, singleDistTmp[toChannelType(compID)], compID, rTu DEBUG_STRING_PASS_INTO(sModeString), default0Save1Load2 ); + } + singleCbfTmp[compID] = pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepth ); + } + //----- determine rate and r-d cost ----- + if(modeId == 1 && singleCbfTmp[COMPONENT_Y] == 0) + { + //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. + singleCostTmp = MAX_DOUBLE; + } + else + { + UInt uiSingleBits = xGetIntraBitsQT( rTu, true, !bLumaOnly, false ); + singleCostTmp = m_pcRdCost->calcRdCost( uiSingleBits, singleDistTmp[CHANNEL_TYPE_LUMA] + singleDistTmp[CHANNEL_TYPE_CHROMA] ); + } + if(singleCostTmp < dSingleCost) + { + DEBUG_STRING_SWAP(sDebug, sModeString) + dSingleCost = singleCostTmp; + uiSingleDist[CHANNEL_TYPE_LUMA] = singleDistTmp[CHANNEL_TYPE_LUMA]; + uiSingleDist[CHANNEL_TYPE_CHROMA] = singleDistTmp[CHANNEL_TYPE_CHROMA]; + for (UInt ch=0; chstore( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] ); + } + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + const Int xOffset = rTu.getRect( COMPONENT_Y ).x0; + const Int yOffset = rTu.getRect( COMPONENT_Y ).y0; + for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++) + { + if (bMaintainResidual[storedResidualIndex]) + { + xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], resiLumaSingle[storedResidualIndex], rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE); + } + } + } + } + if (modeId == firstCheckId) + { + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + } + } + + for(UInt ch=COMPONENT_Y; chsetTransformSkipSubParts ( bestModeId[COMPONENT_Y], compID, uiAbsPartIdx, totalAdjustedDepthChan ); + } + } + + if(bestModeId[COMPONENT_Y] == firstCheckId) + { + xLoadIntraResultQT(COMPONENT_Y, bLumaOnly?COMPONENT_Y:COMPONENT_Cr, rTu ); + for(UInt ch=COMPONENT_Y; ch< numValidComp; ch++) + { + const ComponentID compID=ComponentID(ch); + if (rTu.ProcessComponentSection(compID)) + pcCU->setCbfSubParts ( uiSingleCbf[compID] << uiTrDepth, compID, uiAbsPartIdx, rTu.GetTransformDepthTotalAdj(compID) ); + } + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] ); + } + + if( !bLumaOnly ) + { + bestModeId[COMPONENT_Cb] = bestModeId[COMPONENT_Cr] = bestModeId[COMPONENT_Y]; + if (rTu.ProcessComponentSection(COMPONENT_Cb) && bestModeId[COMPONENT_Y] == 1) + { + //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. + for (UInt ch=COMPONENT_Cb; chsetTransformSkipSubParts ( 0, compID, uiAbsPartIdx, totalAdjustedDepthChan); + bestModeId[ch] = 0; + } + } + } + } + } + else + { + //----- store original entropy coding status ----- + if( bCheckSplit ) + { + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + } + //----- code luma/chroma block with given intra prediction mode and store Cbf----- + dSingleCost = 0.0; + for (UInt ch=COMPONENT_Y; chsetTransformSkipSubParts ( 0, compID, uiAbsPartIdx, totalAdjustedDepthChan ); + } + + xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaSingle, false, uiSingleDist[toChannelType(compID)], compID, rTu DEBUG_STRING_PASS_INTO(sDebug)); + + if( bCheckSplit ) + { + uiSingleCbf[compID] = pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepth ); + } + } + //----- determine rate and r-d cost ----- + UInt uiSingleBits = xGetIntraBitsQT( rTu, true, !bLumaOnly, false ); + + if(m_pcEncCfg->getRDpenalty() && (uiLog2TrSize==5) && !isIntraSlice) + { + uiSingleBits=uiSingleBits*4; + } + + dSingleCost = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDist[CHANNEL_TYPE_LUMA] + uiSingleDist[CHANNEL_TYPE_CHROMA] ); + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + const Int xOffset = rTu.getRect( COMPONENT_Y ).x0; + const Int yOffset = rTu.getRect( COMPONENT_Y ).y0; + for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++) + { + if (bMaintainResidual[storedResidualIndex]) + { + xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], resiLumaSingle[storedResidualIndex], rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE); + } + } + } + } + } + + if( bCheckSplit ) + { + //----- store full entropy coding status, load original entropy coding status ----- + if( bCheckFull ) + { + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] ); + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + } + else + { + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + } + //----- code splitted block ----- + Double dSplitCost = 0.0; + Distortion uiSplitDist[MAX_NUM_CHANNEL_TYPE] = {0,0}; + UInt uiSplitCbf[MAX_NUM_COMPONENT] = {0,0,0}; + + TComTURecurse tuRecurseChild(rTu, false); + DEBUG_STRING_NEW(sSplit) + do + { + DEBUG_STRING_NEW(sChild) +#if HHI_RQT_INTRA_SPEEDUP + xRecurIntraCodingQT( bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaSplit, uiSplitDist[0], uiSplitDist[1], bCheckFirst, dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) ); +#else + xRecurIntraCodingQT( bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaSplit, uiSplitDist[0], uiSplitDist[1], dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) ); +#endif + DEBUG_STRING_APPEND(sSplit, sChild) + for(UInt ch=0; chgetCbf( tuRecurseChild.GetAbsPartIdxTU(), ComponentID(ch), tuRecurseChild.GetTransformDepthRel() ); + } + } while (tuRecurseChild.nextSection(rTu) ); + + UInt uiPartsDiv = rTu.GetAbsPartIdxNumParts(); + for(UInt ch=COMPONENT_Y; chgetCbf( compID ); + for( UInt uiOffs = 0; uiOffs < uiPartsDiv; uiOffs++ ) + { + pBase[ uiAbsPartIdx + uiOffs ] |= flag; + } + } + } + //----- restore context states ----- + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + + //----- determine rate and r-d cost ----- + UInt uiSplitBits = xGetIntraBitsQT( rTu, true, !bLumaOnly, false ); + dSplitCost = m_pcRdCost->calcRdCost( uiSplitBits, uiSplitDist[CHANNEL_TYPE_LUMA] + uiSplitDist[CHANNEL_TYPE_CHROMA] ); + + //===== compare and set best ===== + if( dSplitCost < dSingleCost ) + { + //--- update cost --- + DEBUG_STRING_SWAP(sSplit, sDebug) + ruiDistY += uiSplitDist[CHANNEL_TYPE_LUMA]; + ruiDistC += uiSplitDist[CHANNEL_TYPE_CHROMA]; + dRDCost += dSplitCost; + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + const Int xOffset = rTu.getRect( COMPONENT_Y ).x0; + const Int yOffset = rTu.getRect( COMPONENT_Y ).y0; + for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++) + { + if (bMaintainResidual[storedResidualIndex]) + { + xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], resiLumaSplit[storedResidualIndex], rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE); + } + } + } + + return; + } + + //----- set entropy coding status ----- + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] ); + + //--- set transform index and Cbf values --- + pcCU->setTrIdxSubParts( uiTrDepth, uiAbsPartIdx, uiFullDepth ); + for(UInt ch=0; chsetCbfSubParts ( uiSingleCbf[compID] << uiTrDepth, compID, uiAbsPartIdx, totalAdjustedDepthChan ); + pcCU ->setTransformSkipSubParts ( bestModeId[compID], compID, uiAbsPartIdx, totalAdjustedDepthChan ); + + //--- set reconstruction for next intra prediction blocks --- + const UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + const UInt uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx; + const UInt uiWidth = tuRect.width; + const UInt uiHeight = tuRect.height; + Pel* piSrc = m_pcQTTempTComYuv[ uiQTLayer ].getAddr( compID, uiAbsPartIdx ); + UInt uiSrcStride = m_pcQTTempTComYuv[ uiQTLayer ].getStride ( compID ); + Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder ); + UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride ( compID ); + + for( UInt uiY = 0; uiY < uiHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + piDes[ uiX ] = piSrc[ uiX ]; + } + } + } + } + ruiDistY += uiSingleDist[CHANNEL_TYPE_LUMA]; + ruiDistC += uiSingleDist[CHANNEL_TYPE_CHROMA]; + dRDCost += dSingleCost; +} + + +Void +TEncSearch::xSetIntraResultQT(Bool bLumaOnly, + TComYuv* pcRecoYuv, + TComTU &rTu) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + if( uiTrMode == uiTrDepth ) + { + UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + + Bool bSkipChroma = !rTu.ProcessChannelSection(CHANNEL_TYPE_CHROMA); + + //===== copy transform coefficients ===== + + const UInt numChannelsToProcess = (bLumaOnly || bSkipChroma) ? 1 : ::getNumberValidComponents(pcCU->getPic()->getChromaFormat()); + for (UInt ch=0; chgetCoeff(compID) + coeffOffset; + ::memcpy( destCoeff, srcCoeff, sizeof(TCoeff)*numCoeffInBlock ); +#if ADAPTIVE_QP_SELECTION + const TCoeff* srcArlCoeff = m_ppcQTTempArlCoeff[compID][ uiQTLayer ] + coeffOffset; + TCoeff* destArlCoeff = pcCU->getArlCoeff (compID) + coeffOffset; + ::memcpy( destArlCoeff, srcArlCoeff, sizeof( TCoeff ) * numCoeffInBlock ); +#endif + m_pcQTTempTComYuv[ uiQTLayer ].copyPartToPartComponent( compID, pcRecoYuv, uiAbsPartIdx, tuRect.width, tuRect.height ); + } + } // End of channel loop + + } + else + { + TComTURecurse tuRecurseChild(rTu, false); + do + { + xSetIntraResultQT( bLumaOnly, pcRecoYuv, tuRecurseChild ); + } while (tuRecurseChild.nextSection(rTu)); + } +} + + +Void +TEncSearch::xStoreIntraResultQT(const ComponentID first, + const ComponentID lastIncl, + TComTU &rTu ) +{ + TComDataCU *pcCU=rTu.getCU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + if ( first==COMPONENT_Y || uiTrMode == uiTrDepth ) + { + assert(uiTrMode == uiTrDepth); + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + const UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + + + for(UInt compID_=first; compID_<=lastIncl; compID_++) + { + ComponentID compID=ComponentID(compID_); + if (rTu.ProcessComponentSection(compID)) + { + const TComRectangle &tuRect=rTu.getRect(compID); + + //===== copy transform coefficients ===== + const UInt uiNumCoeff = tuRect.width * tuRect.height; + TCoeff* pcCoeffSrc = m_ppcQTTempCoeff[compID] [ uiQTLayer ] + rTu.getCoefficientOffset(compID); + TCoeff* pcCoeffDst = m_pcQTTempTUCoeff[compID]; + + ::memcpy( pcCoeffDst, pcCoeffSrc, sizeof( TCoeff ) * uiNumCoeff ); +#if ADAPTIVE_QP_SELECTION + TCoeff* pcArlCoeffSrc = m_ppcQTTempArlCoeff[compID] [ uiQTLayer ] + rTu.getCoefficientOffset(compID); + TCoeff* pcArlCoeffDst = m_ppcQTTempTUArlCoeff[compID]; + ::memcpy( pcArlCoeffDst, pcArlCoeffSrc, sizeof( TCoeff ) * uiNumCoeff ); +#endif + //===== copy reconstruction ===== + m_pcQTTempTComYuv[ uiQTLayer ].copyPartToPartComponent( compID, &m_pcQTTempTransformSkipTComYuv, uiAbsPartIdx, tuRect.width, tuRect.height ); + } + } + } +} + + +Void +TEncSearch::xLoadIntraResultQT(const ComponentID first, + const ComponentID lastIncl, + TComTU &rTu) +{ + TComDataCU *pcCU=rTu.getCU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + if ( first==COMPONENT_Y || uiTrMode == uiTrDepth ) + { + assert(uiTrMode == uiTrDepth); + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + const UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + const UInt uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx; + + for(UInt compID_=first; compID_<=lastIncl; compID_++) + { + ComponentID compID=ComponentID(compID_); + if (rTu.ProcessComponentSection(compID)) + { + const TComRectangle &tuRect=rTu.getRect(compID); + + //===== copy transform coefficients ===== + const UInt uiNumCoeff = tuRect.width * tuRect.height; + TCoeff* pcCoeffDst = m_ppcQTTempCoeff[compID] [ uiQTLayer ] + rTu.getCoefficientOffset(compID); + TCoeff* pcCoeffSrc = m_pcQTTempTUCoeff[compID]; + + ::memcpy( pcCoeffDst, pcCoeffSrc, sizeof( TCoeff ) * uiNumCoeff ); +#if ADAPTIVE_QP_SELECTION + TCoeff* pcArlCoeffDst = m_ppcQTTempArlCoeff[compID] [ uiQTLayer ] + rTu.getCoefficientOffset(compID); + TCoeff* pcArlCoeffSrc = m_ppcQTTempTUArlCoeff[compID]; + ::memcpy( pcArlCoeffDst, pcArlCoeffSrc, sizeof( TCoeff ) * uiNumCoeff ); +#endif + //===== copy reconstruction ===== + m_pcQTTempTransformSkipTComYuv.copyPartToPartComponent( compID, &m_pcQTTempTComYuv[ uiQTLayer ], uiAbsPartIdx, tuRect.width, tuRect.height ); + + Pel* piRecIPred = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder ); + UInt uiRecIPredStride = pcCU->getPic()->getPicYuvRec()->getStride (compID); + Pel* piRecQt = m_pcQTTempTComYuv[ uiQTLayer ].getAddr( compID, uiAbsPartIdx ); + UInt uiRecQtStride = m_pcQTTempTComYuv[ uiQTLayer ].getStride (compID); + UInt uiWidth = tuRect.width; + UInt uiHeight = tuRect.height; + Pel* pRecQt = piRecQt; + Pel* pRecIPred = piRecIPred; + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + pRecIPred[ uiX ] = pRecQt [ uiX ]; + } + pRecQt += uiRecQtStride; + pRecIPred += uiRecIPredStride; + } + } + } + } +} + +Void +TEncSearch::xStoreCrossComponentPredictionResult( Pel *pResiDst, + const Pel *pResiSrc, + TComTU &rTu, + const Int xOffset, + const Int yOffset, + const Int strideDst, + const Int strideSrc ) +{ + const Pel *pSrc = pResiSrc + yOffset * strideSrc + xOffset; + Pel *pDst = pResiDst + yOffset * strideDst + xOffset; + + for( Int y = 0; y < rTu.getRect( COMPONENT_Y ).height; y++ ) + { + ::memcpy( pDst, pSrc, sizeof(Pel) * rTu.getRect( COMPONENT_Y ).width ); + pDst += strideDst; + pSrc += strideSrc; + } +} + +Char +TEncSearch::xCalcCrossComponentPredictionAlpha( TComTU &rTu, + const ComponentID compID, + const Pel* piResiL, + const Pel* piResiC, + const Int width, + const Int height, + const Int strideL, + const Int strideC ) +{ + const Pel *pResiL = piResiL; + const Pel *pResiC = piResiC; + + TComDataCU *pCU = rTu.getCU(); + const Int absPartIdx = rTu.GetAbsPartIdxTU( compID ); + const Int diffBitDepth = pCU->getSlice()->getSPS()->getDifferentialLumaChromaBitDepth(); + + Char alpha = 0; + Int SSxy = 0; + Int SSxx = 0; + + for( UInt uiY = 0; uiY < height; uiY++ ) + { + for( UInt uiX = 0; uiX < width; uiX++ ) + { + const Pel scaledResiL = rightShift( pResiL[ uiX ], diffBitDepth ); + SSxy += ( scaledResiL * pResiC[ uiX ] ); + SSxx += ( scaledResiL * scaledResiL ); + } + + pResiL += strideL; + pResiC += strideC; + } + + if( SSxx != 0 ) + { + Double dAlpha = SSxy / Double( SSxx ); + alpha = Char(Clip3(-16, 16, (Int)(dAlpha * 16))); + + static const Char alphaQuant[17] = {0, 1, 1, 2, 2, 2, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8}; + + alpha = (alpha < 0) ? -alphaQuant[Int(-alpha)] : alphaQuant[Int(alpha)]; + } + pCU->setCrossComponentPredictionAlphaPartRange( alpha, compID, absPartIdx, rTu.GetAbsPartIdxNumParts( compID ) ); + + return alpha; +} + +Void +TEncSearch::xRecurIntraChromaCodingQT(TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion& ruiDist, + TComTU& rTu + DEBUG_STRING_FN_DECLARE(sDebug)) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const ChromaFormat format = rTu.GetChromaFormat(); + UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + const UInt numberValidComponents = getNumberValidComponents(format); + + if( uiTrMode == uiTrDepth ) + { + if (!rTu.ProcessChannelSection(CHANNEL_TYPE_CHROMA)) return; + + const UInt uiFullDepth = rTu.GetTransformDepthTotal(); + + Bool checkTransformSkip = pcCU->getSlice()->getPPS()->getUseTransformSkip(); + checkTransformSkip &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Cb), pcCU->getSlice()->getPPS()->getTransformSkipLog2MaxSize()); + + if ( m_pcEncCfg->getUseTransformSkipFast() ) + { + checkTransformSkip &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getTransformSkipLog2MaxSize()); + + if (checkTransformSkip) + { + Int nbLumaSkip = 0; + const UInt maxAbsPartIdxSub=uiAbsPartIdx + (rTu.ProcessingAllQuadrants(COMPONENT_Cb)?1:4); + for(UInt absPartIdxSub = uiAbsPartIdx; absPartIdxSub < maxAbsPartIdxSub; absPartIdxSub ++) + { + nbLumaSkip += pcCU->getTransformSkip(absPartIdxSub, COMPONENT_Y); + } + checkTransformSkip &= (nbLumaSkip > 0); + } + } + + + for (UInt ch=COMPONENT_Cb; chstore( m_pppcRDSbacCoder[uiFullDepth][CI_QT_TRAFO_ROOT] ); + + const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height; + + TComTURecurse TUIterator(rTu, false, (splitIntoSubTUs ? TComTU::VERTICAL_SPLIT : TComTU::DONT_SPLIT), true, compID); + + const UInt partIdxesPerSubTU = TUIterator.GetAbsPartIdxNumParts(compID); + + do + { + const UInt subTUAbsPartIdx = TUIterator.GetAbsPartIdxTU(compID); + + Double dSingleCost = MAX_DOUBLE; + Int bestModeId = 0; + Distortion singleDistC = 0; + UInt singleCbfC = 0; + Distortion singleDistCTmp = 0; + Double singleCostTmp = 0; + UInt singleCbfCTmp = 0; + Char bestCrossCPredictionAlpha = 0; + Int bestTransformSkipMode = 0; + + const Bool checkCrossComponentPrediction = (pcCU->getIntraDir(CHANNEL_TYPE_CHROMA, subTUAbsPartIdx) == DM_CHROMA_IDX) + && pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction() + && (pcCU->getCbf(subTUAbsPartIdx, COMPONENT_Y, uiTrDepth) != 0); + + const Int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1; + const Int transformSkipModesToTest = checkTransformSkip ? 2 : 1; + const Int totalModesToTest = crossCPredictionModesToTest * transformSkipModesToTest; + Int currModeId = 0; + Int default0Save1Load2 = 0; + + for(Int transformSkipModeId = 0; transformSkipModeId < transformSkipModesToTest; transformSkipModeId++) + { + for(Int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++) + { + pcCU->setCrossComponentPredictionAlphaPartRange(0, compID, subTUAbsPartIdx, partIdxesPerSubTU); + DEBUG_STRING_NEW(sDebugMode) + pcCU->setTransformSkipPartRange( transformSkipModeId, compID, subTUAbsPartIdx, partIdxesPerSubTU ); + currModeId++; + + const Bool isOneMode = (totalModesToTest == 1); + const Bool isLastMode = (currModeId == totalModesToTest); // currModeId is indexed from 1 + + if (isOneMode) + { + default0Save1Load2 = 0; + } + else if (!isOneMode && (transformSkipModeId == 0) && (crossCPredictionModeId == 0)) + { + default0Save1Load2 = 1; //save prediction on first mode + } + else + { + default0Save1Load2 = 2; //load it on subsequent modes + } + + singleDistCTmp = 0; + + xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, resiLuma, (crossCPredictionModeId != 0), singleDistCTmp, compID, TUIterator DEBUG_STRING_PASS_INTO(sDebugMode), default0Save1Load2); + singleCbfCTmp = pcCU->getCbf( subTUAbsPartIdx, compID, uiTrDepth); + + if ( ((crossCPredictionModeId == 1) && (pcCU->getCrossComponentPredictionAlpha(subTUAbsPartIdx, compID) == 0)) + || ((transformSkipModeId == 1) && (singleCbfCTmp == 0))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. + { + singleCostTmp = MAX_DOUBLE; + } + else if (!isOneMode) + { + UInt bitsTmp = xGetIntraBitsQTChroma( TUIterator, compID, false ); + singleCostTmp = m_pcRdCost->calcRdCost( bitsTmp, singleDistCTmp); + } + + if(singleCostTmp < dSingleCost) + { + DEBUG_STRING_SWAP(sDebugBestMode, sDebugMode) + dSingleCost = singleCostTmp; + singleDistC = singleDistCTmp; + bestCrossCPredictionAlpha = (crossCPredictionModeId != 0) ? pcCU->getCrossComponentPredictionAlpha(subTUAbsPartIdx, compID) : 0; + bestTransformSkipMode = transformSkipModeId; + bestModeId = currModeId; + singleCbfC = singleCbfCTmp; + + if (!isOneMode && !isLastMode) + { + xStoreIntraResultQT(compID, compID, TUIterator); + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] ); + } + } + + if (!isOneMode && !isLastMode) + { + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] ); + } + } + } + + if(bestModeId < totalModesToTest) + { + xLoadIntraResultQT(compID, compID, TUIterator); + pcCU->setCbfPartRange( singleCbfC << uiTrDepth, compID, subTUAbsPartIdx, partIdxesPerSubTU ); + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] ); + } + + DEBUG_STRING_APPEND(sDebug, sDebugBestMode) + pcCU ->setTransformSkipPartRange ( bestTransformSkipMode, compID, subTUAbsPartIdx, partIdxesPerSubTU ); + pcCU ->setCrossComponentPredictionAlphaPartRange( bestCrossCPredictionAlpha, compID, subTUAbsPartIdx, partIdxesPerSubTU ); + ruiDist += singleDistC; + } + while (TUIterator.nextSection(rTu)); + + if (splitIntoSubTUs) offsetSubTUCBFs(rTu, compID); + } + } + else + { + UInt uiSplitCbf[MAX_NUM_COMPONENT] = {0,0,0}; + + TComTURecurse tuRecurseChild(rTu, false); + const UInt uiTrDepthChild = tuRecurseChild.GetTransformDepthRel(); + do + { + DEBUG_STRING_NEW(sChild) + + xRecurIntraChromaCodingQT( pcOrgYuv, pcPredYuv, pcResiYuv, resiLuma, ruiDist, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) ); + + DEBUG_STRING_APPEND(sDebug, sChild) + const UInt uiAbsPartIdxSub=tuRecurseChild.GetAbsPartIdxTU(); + + for(UInt ch=COMPONENT_Cb; chgetCbf( uiAbsPartIdxSub, ComponentID(ch), uiTrDepthChild ); + } + } while ( tuRecurseChild.nextSection(rTu) ); + + + UInt uiPartsDiv = rTu.GetAbsPartIdxNumParts(); + for(UInt ch=COMPONENT_Cb; chgetCbf( compID ); + for( UInt uiOffs = 0; uiOffs < uiPartsDiv; uiOffs++ ) + { + pBase[ uiAbsPartIdx + uiOffs ] |= flag; + } + } + } + } +} + + + + +Void +TEncSearch::xSetIntraResultChromaQT(TComYuv* pcRecoYuv, TComTU &rTu) +{ + if (!rTu.ProcessChannelSection(CHANNEL_TYPE_CHROMA)) return; + TComDataCU *pcCU=rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiTrDepth = rTu.GetTransformDepthRel(); + UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + if( uiTrMode == uiTrDepth ) + { + UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + + //===== copy transform coefficients ===== + const TComRectangle &tuRectCb=rTu.getRect(COMPONENT_Cb); + UInt uiNumCoeffC = tuRectCb.width*tuRectCb.height;//( pcCU->getSlice()->getSPS()->getMaxCUWidth() * pcCU->getSlice()->getSPS()->getMaxCUHeight() ) >> ( uiFullDepth << 1 ); + const UInt offset = rTu.getCoefficientOffset(COMPONENT_Cb); + + const UInt numberValidComponents = getNumberValidComponents(rTu.GetChromaFormat()); + for (UInt ch=COMPONENT_Cb; chgetCoeff(component) + offset;//(uiNumCoeffIncC*uiAbsPartIdx); + ::memcpy( dest, src, sizeof(TCoeff)*uiNumCoeffC ); +#if ADAPTIVE_QP_SELECTION + TCoeff* pcArlCoeffSrc = m_ppcQTTempArlCoeff[component][ uiQTLayer ] + offset;//( uiNumCoeffIncC * uiAbsPartIdx ); + TCoeff* pcArlCoeffDst = pcCU->getArlCoeff(component) + offset;//( uiNumCoeffIncC * uiAbsPartIdx ); + ::memcpy( pcArlCoeffDst, pcArlCoeffSrc, sizeof( TCoeff ) * uiNumCoeffC ); +#endif + } + + //===== copy reconstruction ===== + + m_pcQTTempTComYuv[ uiQTLayer ].copyPartToPartComponent( COMPONENT_Cb, pcRecoYuv, uiAbsPartIdx, tuRectCb.width, tuRectCb.height ); + m_pcQTTempTComYuv[ uiQTLayer ].copyPartToPartComponent( COMPONENT_Cr, pcRecoYuv, uiAbsPartIdx, tuRectCb.width, tuRectCb.height ); + } + else + { + TComTURecurse tuRecurseChild(rTu, false); + do + { + xSetIntraResultChromaQT( pcRecoYuv, tuRecurseChild ); + } while (tuRecurseChild.nextSection(rTu)); + } +} + + + +Void +TEncSearch::preestChromaPredMode( TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv ) +{ + + //===== loop over partitions ===== + const UInt uiInitTrDepth = pcCU->getPartitionSize(0) != SIZE_2Nx2N && enable4ChromaPUsInIntraNxNCU(pcOrgYuv->getChromaFormat()) ? 1 : 0; + TComTURecurse tuRecurseCU(pcCU, 0); + TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT); + const ChromaFormat chFmt = tuRecurseWithPU.GetChromaFormat(); + Bool bFilterEnabled=filterIntraReferenceSamples(CHANNEL_TYPE_CHROMA, chFmt, pcCU->getSlice()->getSPS()->getDisableIntraReferenceSmoothing()); + + do + { + if (tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA)) + { + const TComRectangle &rect=tuRecurseWithPU.getRect(COMPONENT_Cb); + const UInt uiWidth = rect.width; + const UInt uiHeight = rect.height; + const UInt partIdx = tuRecurseWithPU.GetAbsPartIdxCU(); + const UInt uiStride = pcOrgYuv ->getStride(COMPONENT_Cb); + Pel* piOrgU = pcOrgYuv ->getAddr ( COMPONENT_Cb, partIdx ); //TODO: Change this into an array and loop over chroma components below + Pel* piOrgV = pcOrgYuv ->getAddr ( COMPONENT_Cr, partIdx ); + Pel* piPredU = pcPredYuv->getAddr ( COMPONENT_Cb, partIdx ); + Pel* piPredV = pcPredYuv->getAddr ( COMPONENT_Cr, partIdx ); + + //===== init pattern ===== + Bool bAboveAvail = false; + Bool bLeftAvail = false; + DEBUG_STRING_NEW(sTemp) + initAdiPatternChType( tuRecurseWithPU, bAboveAvail, bLeftAvail, COMPONENT_Cb, bFilterEnabled DEBUG_STRING_PASS_INTO(sTemp) ); + initAdiPatternChType( tuRecurseWithPU, bAboveAvail, bLeftAvail, COMPONENT_Cr, bFilterEnabled DEBUG_STRING_PASS_INTO(sTemp) ); + + //===== get best prediction modes (using SAD) ===== + UInt uiMinMode = 0; + UInt uiMaxMode = 4; + UInt uiBestMode = MAX_UINT; + Distortion uiMinSAD = std::numeric_limits::max(); + const UInt mappedModeTable[4] = {PLANAR_IDX,DC_IDX,HOR_IDX,VER_IDX}; + + DistParam distParamU, distParamV; + const Bool bUseHadamard=pcCU->getCUTransquantBypass(0) == 0; + m_pcRdCost->setDistParam(distParamU, g_bitDepth[CHANNEL_TYPE_CHROMA], piOrgU, uiStride, piPredU, uiStride, uiWidth, uiHeight, bUseHadamard); + m_pcRdCost->setDistParam(distParamV, g_bitDepth[CHANNEL_TYPE_CHROMA], piOrgV, uiStride, piPredV, uiStride, uiWidth, uiHeight, bUseHadamard); + distParamU.bApplyWeight = false; + distParamV.bApplyWeight = false; + + for( UInt uiMode_ = uiMinMode; uiMode_ < uiMaxMode; uiMode_++ ) + { + UInt uiMode=mappedModeTable[uiMode_]; + //--- get prediction --- + const Bool bUseFilter=TComPrediction::filteringIntraReferenceSamples(COMPONENT_Cb, uiMode, uiWidth, uiHeight, chFmt, pcCU->getSlice()->getSPS()->getDisableIntraReferenceSmoothing()); + + predIntraAng( COMPONENT_Cb, uiMode, piOrgU, uiStride, piPredU, uiStride, tuRecurseCU, bAboveAvail, bLeftAvail, bUseFilter ); + predIntraAng( COMPONENT_Cr, uiMode, piOrgV, uiStride, piPredV, uiStride, tuRecurseCU, bAboveAvail, bLeftAvail, bUseFilter ); + + //--- get SAD --- + Distortion uiSAD = distParamU.DistFunc(&distParamU); + uiSAD += distParamV.DistFunc(&distParamV); + //--- check --- + if( uiSAD < uiMinSAD ) + { + uiMinSAD = uiSAD; + uiBestMode = uiMode; + } + } + + //===== set chroma pred mode ===== + pcCU->setIntraDirSubParts( CHANNEL_TYPE_CHROMA, uiBestMode, partIdx, tuRecurseWithPU.getCUDepth() + uiInitTrDepth ); + } + } while (tuRecurseWithPU.nextSection(tuRecurseCU)); +} + + + + +Void +TEncSearch::estIntraPredQT(TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + TComYuv* pcRecoYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion& ruiDistC, + Bool bLumaOnly + DEBUG_STRING_FN_DECLARE(sDebug)) +{ + const UInt uiDepth = pcCU->getDepth(0); + const UInt uiInitTrDepth = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1; + const UInt uiInitTrDepthC = pcCU->getPartitionSize(0) != SIZE_2Nx2N && enable4ChromaPUsInIntraNxNCU(pcOrgYuv->getChromaFormat()) ? 1 : 0; + const UInt uiNumPU = 1<<(2*uiInitTrDepth); + const UInt uiQNumParts = pcCU->getTotalNumPart() >> 2; + const UInt uiWidthBit = pcCU->getIntraSizeIdx(0); + const ChromaFormat chFmt = pcCU->getPic()->getChromaFormat(); + const UInt numberValidComponents = getNumberValidComponents(chFmt); + Distortion uiOverallDistY = 0; + Distortion uiOverallDistC = 0; + UInt CandNum; + Double CandCostList[ FAST_UDI_MAX_RDMODE_NUM ]; + Pel resiLumaPU[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]; + + Bool bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES]; + for (UInt residualTypeIndex = 0; residualTypeIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; residualTypeIndex++) + { + bMaintainResidual[residualTypeIndex] = true; //assume true unless specified otherwise + } + + bMaintainResidual[RESIDUAL_ENCODER_SIDE] = !(m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate()); + + // Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantisation divisor is 1. +#if FULL_NBIT + const Double sqrtLambdaForFirstPass= (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING && pcCU->getCUTransquantBypass(0)) ? + sqrt(0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12) / 3.0))) + : m_pcRdCost->getSqrtLambda(); +#else + const Double sqrtLambdaForFirstPass= (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING && pcCU->getCUTransquantBypass(0)) ? + sqrt(0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12 - 6 * (g_bitDepth[CHANNEL_TYPE_LUMA] - 8)) / 3.0))) + : m_pcRdCost->getSqrtLambda(); +#endif + + //===== set QP and clear Cbf ===== + if ( pcCU->getSlice()->getPPS()->getUseDQP() == true) + { + pcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth ); + } + else + { + pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth ); + } + + //===== loop over partitions ===== + TComTURecurse tuRecurseCU(pcCU, 0); + TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT); + + do + { + const UInt uiPartOffset=tuRecurseWithPU.GetAbsPartIdxTU(); +// for( UInt uiPU = 0, uiPartOffset=0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts ) + //{ + //===== init pattern for luma prediction ===== + Bool bAboveAvail = false; + Bool bLeftAvail = false; + DEBUG_STRING_NEW(sTemp2) + + //===== determine set of modes to be tested (using prediction signal only) ===== + Int numModesAvailable = 35; //total number of Intra modes + UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM]; + Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ]; + + if (tuRecurseWithPU.ProcessComponentSection(COMPONENT_Y)) + initAdiPatternChType( tuRecurseWithPU, bAboveAvail, bLeftAvail, COMPONENT_Y, true DEBUG_STRING_PASS_INTO(sTemp2) ); + + Bool doFastSearch = (numModesForFullRD != numModesAvailable); + if (doFastSearch) + { + assert(numModesForFullRD < numModesAvailable); + + for( Int i=0; i < numModesForFullRD; i++ ) + { + CandCostList[ i ] = MAX_DOUBLE; + } + CandNum = 0; + + const TComRectangle &puRect=tuRecurseWithPU.getRect(COMPONENT_Y); + const UInt uiAbsPartIdx=tuRecurseWithPU.GetAbsPartIdxTU(); + + Pel* piOrg = pcOrgYuv ->getAddr( COMPONENT_Y, uiAbsPartIdx ); + Pel* piPred = pcPredYuv->getAddr( COMPONENT_Y, uiAbsPartIdx ); + UInt uiStride = pcPredYuv->getStride( COMPONENT_Y ); + DistParam distParam; + const Bool bUseHadamard=pcCU->getCUTransquantBypass(0) == 0; + m_pcRdCost->setDistParam(distParam, g_bitDepth[CHANNEL_TYPE_LUMA], piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard); + distParam.bApplyWeight = false; + for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) + { + UInt uiMode = modeIdx; + Distortion uiSad = 0; + + const Bool bUseFilter=TComPrediction::filteringIntraReferenceSamples(COMPONENT_Y, uiMode, puRect.width, puRect.height, chFmt, pcCU->getSlice()->getSPS()->getDisableIntraReferenceSmoothing()); + + predIntraAng( COMPONENT_Y, uiMode, piOrg, uiStride, piPred, uiStride, tuRecurseWithPU, bAboveAvail, bLeftAvail, bUseFilter, TComPrediction::UseDPCMForFirstPassIntraEstimation(tuRecurseWithPU, uiMode) ); + + // use hadamard transform here + uiSad+=distParam.DistFunc(&distParam); + + UInt iModeBits = 0; + + // NB xModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated. + iModeBits+=xModeBitsIntra( pcCU, uiMode, uiPartOffset, uiDepth, uiInitTrDepth, CHANNEL_TYPE_LUMA ); + + Double cost = (Double)uiSad + (Double)iModeBits * sqrtLambdaForFirstPass; + +#ifdef DEBUG_INTRA_SEARCH_COSTS + std::cout << "1st pass mode " << uiMode << " SAD = " << uiSad << ", mode bits = " << iModeBits << ", cost = " << cost << "\n"; +#endif + + CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList ); + } + +#if FAST_UDI_USE_MPM + Int uiPreds[NUM_MOST_PROBABLE_MODES] = {-1, -1, -1}; + + Int iMode = -1; + Int numCand = pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode ); + + if( iMode >= 0 ) + { + numCand = iMode; + } + + for( Int j=0; j < numCand; j++) + { + Bool mostProbableModeIncluded = false; + Int mostProbableMode = uiPreds[j]; + + for( Int i=0; i < numModesForFullRD; i++) + { + mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]); + } + if (!mostProbableModeIncluded) + { + uiRdModeList[numModesForFullRD++] = mostProbableMode; + } + } +#endif // FAST_UDI_USE_MPM + } + else + { + for( Int i=0; i < numModesForFullRD; i++) + { + uiRdModeList[i] = i; + } + } + + //===== check modes (using r-d costs) ===== +#if HHI_RQT_INTRA_SPEEDUP_MOD + UInt uiSecondBestMode = MAX_UINT; + Double dSecondBestPUCost = MAX_DOUBLE; +#endif + DEBUG_STRING_NEW(sPU) + UInt uiBestPUMode = 0; + Distortion uiBestPUDistY = 0; + Distortion uiBestPUDistC = 0; + Double dBestPUCost = MAX_DOUBLE; + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + UInt max=numModesForFullRD; + + if (DebugOptionList::ForceLumaMode.isSet()) max=0; // we are forcing a direction, so don't bother with mode check + for ( UInt uiMode = 0; uiMode < max; uiMode++) +#else + for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ ) +#endif + { + // set luma prediction mode + UInt uiOrgMode = uiRdModeList[uiMode]; + + pcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth ); + + DEBUG_STRING_NEW(sMode) + // set context models + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] ); + + // determine residual for partition + Distortion uiPUDistY = 0; + Distortion uiPUDistC = 0; + Double dPUCost = 0.0; +#if HHI_RQT_INTRA_SPEEDUP + xRecurIntraCodingQT( bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaPU, uiPUDistY, uiPUDistC, true, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) ); +#else + xRecurIntraCodingQT( bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaPU, uiPUDistY, uiPUDistC, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) ); +#endif + +#ifdef DEBUG_INTRA_SEARCH_COSTS + std::cout << "2nd pass [luma,chroma] mode [" << Int(pcCU->getIntraDir(CHANNEL_TYPE_LUMA, uiPartOffset)) << "," << Int(pcCU->getIntraDir(CHANNEL_TYPE_CHROMA, uiPartOffset)) << "] cost = " << dPUCost << "\n"; +#endif + + // check r-d cost + if( dPUCost < dBestPUCost ) + { + DEBUG_STRING_SWAP(sPU, sMode) +#if HHI_RQT_INTRA_SPEEDUP_MOD + uiSecondBestMode = uiBestPUMode; + dSecondBestPUCost = dBestPUCost; +#endif + uiBestPUMode = uiOrgMode; + uiBestPUDistY = uiPUDistY; + uiBestPUDistC = uiPUDistC; + dBestPUCost = dPUCost; + + xSetIntraResultQT( bLumaOnly, pcRecoYuv, tuRecurseWithPU ); + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + const Int xOffset = tuRecurseWithPU.getRect( COMPONENT_Y ).x0; + const Int yOffset = tuRecurseWithPU.getRect( COMPONENT_Y ).y0; + for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++) + { + if (bMaintainResidual[storedResidualIndex]) + { + xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], resiLumaPU[storedResidualIndex], tuRecurseWithPU, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE ); + } + } + } + + UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts(); + + ::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + for (UInt component = 0; component < numberValidComponents; component++) + { + const ComponentID compID = ComponentID(component); + ::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID ) + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + ::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip(compID) + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + } + } +#if HHI_RQT_INTRA_SPEEDUP_MOD + else if( dPUCost < dSecondBestPUCost ) + { + uiSecondBestMode = uiOrgMode; + dSecondBestPUCost = dPUCost; + } +#endif + } // Mode loop + +#if HHI_RQT_INTRA_SPEEDUP +#if HHI_RQT_INTRA_SPEEDUP_MOD + for( UInt ui =0; ui < 2; ++ui ) +#endif + { +#if HHI_RQT_INTRA_SPEEDUP_MOD + UInt uiOrgMode = ui ? uiSecondBestMode : uiBestPUMode; + if( uiOrgMode == MAX_UINT ) + { + break; + } +#else + UInt uiOrgMode = uiBestPUMode; +#endif + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (DebugOptionList::ForceLumaMode.isSet()) + uiOrgMode = DebugOptionList::ForceLumaMode.getInt(); +#endif + + pcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth ); + DEBUG_STRING_NEW(sModeTree) + + // set context models + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] ); + + // determine residual for partition + Distortion uiPUDistY = 0; + Distortion uiPUDistC = 0; + Double dPUCost = 0.0; + + xRecurIntraCodingQT( bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, resiLumaPU, uiPUDistY, uiPUDistC, false, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sModeTree)); + + // check r-d cost + if( dPUCost < dBestPUCost ) + { + DEBUG_STRING_SWAP(sPU, sModeTree) + uiBestPUMode = uiOrgMode; + uiBestPUDistY = uiPUDistY; + uiBestPUDistC = uiPUDistC; + dBestPUCost = dPUCost; + + xSetIntraResultQT( bLumaOnly, pcRecoYuv, tuRecurseWithPU ); + + if (pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) + { + const Int xOffset = tuRecurseWithPU.getRect( COMPONENT_Y ).x0; + const Int yOffset = tuRecurseWithPU.getRect( COMPONENT_Y ).y0; + for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++) + { + if (bMaintainResidual[storedResidualIndex]) + { + xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], resiLumaPU[storedResidualIndex], tuRecurseWithPU, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE ); + } + } + } + + const UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts(); + ::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + + for (UInt component = 0; component < numberValidComponents; component++) + { + const ComponentID compID = ComponentID(component); + ::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID ) + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + ::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip(compID) + uiPartOffset, uiQPartNum * sizeof( UChar ) ); + } + } + } // Mode loop +#endif + + DEBUG_STRING_APPEND(sDebug, sPU) + + //--- update overall distortion --- + uiOverallDistY += uiBestPUDistY; + uiOverallDistC += uiBestPUDistC; + + //--- update transform index and cbf --- + const UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts(); + ::memcpy( pcCU->getTransformIdx() + uiPartOffset, m_puhQTTempTrIdx, uiQPartNum * sizeof( UChar ) ); + for (UInt component = 0; component < numberValidComponents; component++) + { + const ComponentID compID = ComponentID(component); + ::memcpy( pcCU->getCbf( compID ) + uiPartOffset, m_puhQTTempCbf[compID], uiQPartNum * sizeof( UChar ) ); + ::memcpy( pcCU->getTransformSkip( compID ) + uiPartOffset, m_puhQTTempTransformSkipFlag[compID ], uiQPartNum * sizeof( UChar ) ); + } + + //--- set reconstruction for next intra prediction blocks --- + if( !tuRecurseWithPU.IsLastSection() ) + { + const Bool bSkipChroma = tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA); + + const UInt numChannelToProcess = (bLumaOnly || bSkipChroma) ? 1 : getNumberValidComponents(pcCU->getPic()->getChromaFormat()); + + for (UInt ch=0; chgetZorderIdxInCtu() + uiPartOffset; + Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder ); + const UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride( compID); + const Pel* piSrc = pcRecoYuv->getAddr( compID, uiPartOffset ); + const UInt uiSrcStride = pcRecoYuv->getStride( compID); + + for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ) + { + for( UInt uiX = 0; uiX < uiCompWidth; uiX++ ) + { + piDes[ uiX ] = piSrc[ uiX ]; + } + } + } + } + + //=== update PU data ==== + pcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiBestPUMode, uiPartOffset, uiDepth + uiInitTrDepth ); + if (!bLumaOnly && getChromasCorrespondingPULumaIdx(uiPartOffset, chFmt)==uiPartOffset) + { + UInt chromaDir=pcCU->getIntraDir(CHANNEL_TYPE_CHROMA, getChromasCorrespondingPULumaIdx(uiPartOffset, chFmt)); + if (chromaDir == uiBestPUMode && tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA)) + { + pcCU->setIntraDirSubParts ( CHANNEL_TYPE_CHROMA, DM_CHROMA_IDX, getChromasCorrespondingPULumaIdx(uiPartOffset, chFmt), uiDepth + uiInitTrDepthC ); + } + } + //pcCU->copyToPic ( uiDepth, uiPU, uiInitTrDepth ); // Unnecessary copy? + } while (tuRecurseWithPU.nextSection(tuRecurseCU)); + + + if( uiNumPU > 1 ) + { // set Cbf for all blocks + UInt uiCombCbfY = 0; + UInt uiCombCbfU = 0; + UInt uiCombCbfV = 0; + UInt uiPartIdx = 0; + for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts ) + { + uiCombCbfY |= pcCU->getCbf( uiPartIdx, COMPONENT_Y, 1 ); + uiCombCbfU |= pcCU->getCbf( uiPartIdx, COMPONENT_Cb, 1 ); + uiCombCbfV |= pcCU->getCbf( uiPartIdx, COMPONENT_Cr, 1 ); + } + for( UInt uiOffs = 0; uiOffs < 4 * uiQNumParts; uiOffs++ ) + { + pcCU->getCbf( COMPONENT_Y )[ uiOffs ] |= uiCombCbfY; + pcCU->getCbf( COMPONENT_Cb )[ uiOffs ] |= uiCombCbfU; + pcCU->getCbf( COMPONENT_Cr )[ uiOffs ] |= uiCombCbfV; + } + } + + //===== reset context models ===== + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); + + //===== set distortion (rate and r-d costs are determined later) ===== + ruiDistC = uiOverallDistC; + pcCU->getTotalDistortion() = uiOverallDistY + uiOverallDistC; +} + + + + +Void +TEncSearch::estIntraPredChromaQT(TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + TComYuv* pcRecoYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion uiPreCalcDistC + DEBUG_STRING_FN_DECLARE(sDebug)) +{ + pcCU->getTotalDistortion () -= uiPreCalcDistC; + + //const UInt uiDepthCU = pcCU->getDepth(0); + const UInt uiInitTrDepth = pcCU->getPartitionSize(0) != SIZE_2Nx2N && enable4ChromaPUsInIntraNxNCU(pcOrgYuv->getChromaFormat()) ? 1 : 0; +// const UInt uiNumPU = 1<<(2*uiInitTrDepth); + + TComTURecurse tuRecurseCU(pcCU, 0); + TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT); + const UInt uiQNumParts = tuRecurseWithPU.GetAbsPartIdxNumParts(); + const UInt uiDepthCU=tuRecurseWithPU.getCUDepth(); + const UInt numberValidComponents = pcCU->getPic()->getNumberValidComponents(); + + do + { + UInt uiBestMode = 0; + Distortion uiBestDist = 0; + Double dBestCost = MAX_DOUBLE; + + //----- init mode list ----- + if (tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA)) + { + UInt uiModeList[FAST_UDI_MAX_RDMODE_NUM]; + const UInt uiQPartNum = uiQNumParts; + const UInt uiPartOffset = tuRecurseWithPU.GetAbsPartIdxTU(); + { + UInt uiMinMode = 0; + UInt uiMaxMode = NUM_CHROMA_MODE; + + //----- check chroma modes ----- + pcCU->getAllowedChromaDir( uiPartOffset, uiModeList ); + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + if (DebugOptionList::ForceChromaMode.isSet()) + { + uiMinMode=DebugOptionList::ForceChromaMode.getInt(); + if (uiModeList[uiMinMode]==34) uiMinMode=4; // if the fixed mode has been renumbered because DM_CHROMA covers it, use DM_CHROMA. + uiMaxMode=uiMinMode+1; + } +#endif + + DEBUG_STRING_NEW(sPU) + + for( UInt uiMode = uiMinMode; uiMode < uiMaxMode; uiMode++ ) + { + //----- restore context models ----- + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] ); + + DEBUG_STRING_NEW(sMode) + //----- chroma coding ----- + Distortion uiDist = 0; + pcCU->setIntraDirSubParts ( CHANNEL_TYPE_CHROMA, uiModeList[uiMode], uiPartOffset, uiDepthCU+uiInitTrDepth ); + xRecurIntraChromaCodingQT ( pcOrgYuv, pcPredYuv, pcResiYuv, resiLuma, uiDist, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) ); + + if( pcCU->getSlice()->getPPS()->getUseTransformSkip() ) + { + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] ); + } + + UInt uiBits = xGetIntraBitsQT( tuRecurseWithPU, false, true, false ); + Double dCost = m_pcRdCost->calcRdCost( uiBits, uiDist ); + + //----- compare ----- + if( dCost < dBestCost ) + { + DEBUG_STRING_SWAP(sPU, sMode); + dBestCost = dCost; + uiBestDist = uiDist; + uiBestMode = uiModeList[uiMode]; + + xSetIntraResultChromaQT( pcRecoYuv, tuRecurseWithPU ); + for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++) + { + const ComponentID compID = ComponentID(componentIndex); + ::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) ); + ::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) ); + ::memcpy( m_phQTTempCrossComponentPredictionAlpha[compID], pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, uiQPartNum * sizeof( Char ) ); + } + } + } + + DEBUG_STRING_APPEND(sDebug, sPU) + + //----- set data ----- + for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++) + { + const ComponentID compID = ComponentID(componentIndex); + ::memcpy( pcCU->getCbf( compID )+uiPartOffset, m_puhQTTempCbf[compID], uiQPartNum * sizeof( UChar ) ); + ::memcpy( pcCU->getTransformSkip( compID )+uiPartOffset, m_puhQTTempTransformSkipFlag[compID], uiQPartNum * sizeof( UChar ) ); + ::memcpy( pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, m_phQTTempCrossComponentPredictionAlpha[compID], uiQPartNum * sizeof( Char ) ); + } + } + + if( ! tuRecurseWithPU.IsLastSection() ) + { + for (UInt ch=COMPONENT_Cb; chgetZorderIdxInCtu() + tuRecurseWithPU.GetAbsPartIdxTU(); + Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder ); + const UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride( compID); + const Pel* piSrc = pcRecoYuv->getAddr( compID, uiPartOffset ); + const UInt uiSrcStride = pcRecoYuv->getStride( compID); + + for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ) + { + for( UInt uiX = 0; uiX < uiCompWidth; uiX++ ) + { + piDes[ uiX ] = piSrc[ uiX ]; + } + } + } + } + + pcCU->setIntraDirSubParts( CHANNEL_TYPE_CHROMA, uiBestMode, uiPartOffset, uiDepthCU+uiInitTrDepth ); + pcCU->getTotalDistortion () += uiBestDist; + } + + } while (tuRecurseWithPU.nextSection(tuRecurseCU)); + + //----- restore context models ----- + + if( uiInitTrDepth != 0 ) + { // set Cbf for all blocks + UInt uiCombCbfU = 0; + UInt uiCombCbfV = 0; + UInt uiPartIdx = 0; + for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts ) + { + uiCombCbfU |= pcCU->getCbf( uiPartIdx, COMPONENT_Cb, 1 ); + uiCombCbfV |= pcCU->getCbf( uiPartIdx, COMPONENT_Cr, 1 ); + } + for( UInt uiOffs = 0; uiOffs < 4 * uiQNumParts; uiOffs++ ) + { + pcCU->getCbf( COMPONENT_Cb )[ uiOffs ] |= uiCombCbfU; + pcCU->getCbf( COMPONENT_Cr )[ uiOffs ] |= uiCombCbfV; + } + } + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] ); +} + + + + +/** Function for encoding and reconstructing luma/chroma samples of a PCM mode CU. + * \param pcCU pointer to current CU + * \param uiAbsPartIdx part index + * \param piOrg pointer to original sample arrays + * \param piPCM pointer to PCM code arrays + * \param piPred pointer to prediction signal arrays + * \param piResi pointer to residual signal arrays + * \param piReco pointer to reconstructed sample arrays + * \param uiStride stride of the original/prediction/residual sample arrays + * \param uiWidth block width + * \param uiHeight block height + * \param ttText texture component type + * \returns Void + */ +Void TEncSearch::xEncPCM (TComDataCU* pcCU, UInt uiAbsPartIdx, Pel* pOrg, Pel* pPCM, Pel* pPred, Pel* pResi, Pel* pReco, UInt uiStride, UInt uiWidth, UInt uiHeight, const ComponentID compID ) +{ + const UInt uiReconStride = pcCU->getPic()->getPicYuvRec()->getStride(compID); + const UInt uiPCMBitDepth = pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID)); + Pel* pRecoPic = pcCU->getPic()->getPicYuvRec()->getAddr(compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu()+uiAbsPartIdx); + + const Int pcmShiftRight=(g_bitDepth[toChannelType(compID)] - Int(uiPCMBitDepth)); + + assert(pcmShiftRight >= 0); + + for( UInt uiY = 0; uiY < uiHeight; uiY++ ) + { + for( UInt uiX = 0; uiX < uiWidth; uiX++ ) + { + // Reset pred and residual + pPred[uiX] = 0; + pResi[uiX] = 0; + // Encode + pPCM[uiX] = (pOrg[uiX]>>pcmShiftRight); + // Reconstruction + pReco [uiX] = (pPCM[uiX]<<(pcmShiftRight)); + pRecoPic[uiX] = pReco[uiX]; + } + pPred += uiStride; + pResi += uiStride; + pPCM += uiWidth; + pOrg += uiStride; + pReco += uiStride; + pRecoPic += uiReconStride; + } +} + + +/** Function for PCM mode estimation. + * \param pcCU + * \param pcOrgYuv + * \param rpcPredYuv + * \param rpcResiYuv + * \param rpcRecoYuv + * \returns Void + */ +Void TEncSearch::IPCMSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv ) +{ + UInt uiDepth = pcCU->getDepth(0); + const UInt uiDistortion = 0; + UInt uiBits; + + Double dCost; + + for (UInt ch=0; ch < pcCU->getPic()->getNumberValidComponents(); ch++) + { + const ComponentID compID = ComponentID(ch); + const UInt width = pcCU->getWidth(0) >> pcCU->getPic()->getComponentScaleX(compID); + const UInt height = pcCU->getHeight(0) >> pcCU->getPic()->getComponentScaleY(compID); + const UInt stride = pcPredYuv->getStride(compID); + + Pel * pOrig = pcOrgYuv->getAddr (compID, 0, width); + Pel * pResi = pcResiYuv->getAddr(compID, 0, width); + Pel * pPred = pcPredYuv->getAddr(compID, 0, width); + Pel * pReco = pcRecoYuv->getAddr(compID, 0, width); + Pel * pPCM = pcCU->getPCMSample (compID); + + xEncPCM ( pcCU, 0, pOrig, pPCM, pPred, pResi, pReco, stride, width, height, compID ); + + } + + m_pcEntropyCoder->resetBits(); + xEncIntraHeader ( pcCU, uiDepth, 0, true, false); + uiBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + + dCost = m_pcRdCost->calcRdCost( uiBits, uiDistortion ); + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); + + pcCU->getTotalBits() = uiBits; + pcCU->getTotalCost() = dCost; + pcCU->getTotalDistortion() = uiDistortion; + + pcCU->copyToPic(uiDepth, 0, 0); +} + + + + +Void TEncSearch::xGetInterPredictionError( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, Distortion& ruiErr, Bool /*bHadamard*/ ) +{ + motionCompensation( pcCU, &m_tmpYuvPred, REF_PIC_LIST_X, iPartIdx ); + + UInt uiAbsPartIdx = 0; + Int iWidth = 0; + Int iHeight = 0; + pcCU->getPartIndexAndSize( iPartIdx, uiAbsPartIdx, iWidth, iHeight ); + + DistParam cDistParam; + + cDistParam.bApplyWeight = false; + + + m_pcRdCost->setDistParam( cDistParam, g_bitDepth[CHANNEL_TYPE_LUMA], + pcYuvOrg->getAddr( COMPONENT_Y, uiAbsPartIdx ), pcYuvOrg->getStride(COMPONENT_Y), + m_tmpYuvPred .getAddr( COMPONENT_Y, uiAbsPartIdx ), m_tmpYuvPred.getStride(COMPONENT_Y), + iWidth, iHeight, m_pcEncCfg->getUseHADME() && (pcCU->getCUTransquantBypass(iPartIdx) == 0) ); + + ruiErr = cDistParam.DistFunc( &cDistParam ); +} + +/** estimation of best merge coding + * \param pcCU + * \param pcYuvOrg + * \param iPUIdx + * \param uiInterDir + * \param pacMvField + * \param uiMergeIndex + * \param ruiCost + * \param ruiBits + * \param puhNeighCands + * \param bValid + * \returns Void + */ +Void TEncSearch::xMergeEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPUIdx, UInt& uiInterDir, TComMvField* pacMvField, UInt& uiMergeIndex, Distortion& ruiCost, TComMvField* cMvFieldNeighbours, UChar* uhInterDirNeighbours, Int& numValidMergeCand ) +{ + UInt uiAbsPartIdx = 0; + Int iWidth = 0; + Int iHeight = 0; + + pcCU->getPartIndexAndSize( iPUIdx, uiAbsPartIdx, iWidth, iHeight ); + UInt uiDepth = pcCU->getDepth( uiAbsPartIdx ); + + PartSize partSize = pcCU->getPartitionSize( 0 ); + if ( pcCU->getSlice()->getPPS()->getLog2ParallelMergeLevelMinus2() && partSize != SIZE_2Nx2N && pcCU->getWidth( 0 ) <= 8 ) + { + pcCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uiDepth ); + if ( iPUIdx == 0 ) + { + pcCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand ); + } + pcCU->setPartSizeSubParts( partSize, 0, uiDepth ); + } + else + { + pcCU->getInterMergeCandidates( uiAbsPartIdx, iPUIdx, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand ); + } + + xRestrictBipredMergeCand( pcCU, iPUIdx, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand ); + + ruiCost = std::numeric_limits::max(); + for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand ) + { + Distortion uiCostCand = std::numeric_limits::max(); + UInt uiBitsCand = 0; + + PartSize ePartSize = pcCU->getPartitionSize( 0 ); + + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], ePartSize, uiAbsPartIdx, 0, iPUIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], ePartSize, uiAbsPartIdx, 0, iPUIdx ); + + xGetInterPredictionError( pcCU, pcYuvOrg, iPUIdx, uiCostCand, m_pcEncCfg->getUseHADME() ); + uiBitsCand = uiMergeCand + 1; + if (uiMergeCand == m_pcEncCfg->getMaxNumMergeCand() -1) + { + uiBitsCand--; + } + uiCostCand = uiCostCand + m_pcRdCost->getCost( uiBitsCand ); + if ( uiCostCand < ruiCost ) + { + ruiCost = uiCostCand; + pacMvField[0] = cMvFieldNeighbours[0 + 2*uiMergeCand]; + pacMvField[1] = cMvFieldNeighbours[1 + 2*uiMergeCand]; + uiInterDir = uhInterDirNeighbours[uiMergeCand]; + uiMergeIndex = uiMergeCand; + } + } +} + +/** convert bi-pred merge candidates to uni-pred + * \param pcCU + * \param puIdx + * \param mvFieldNeighbours + * \param interDirNeighbours + * \param numValidMergeCand + * \returns Void + */ +Void TEncSearch::xRestrictBipredMergeCand( TComDataCU* pcCU, UInt puIdx, TComMvField* mvFieldNeighbours, UChar* interDirNeighbours, Int numValidMergeCand ) +{ + if ( pcCU->isBipredRestriction(puIdx) ) + { + for( UInt mergeCand = 0; mergeCand < numValidMergeCand; ++mergeCand ) + { + if ( interDirNeighbours[mergeCand] == 3 ) + { + interDirNeighbours[mergeCand] = 1; + mvFieldNeighbours[(mergeCand << 1) + 1].setMvField(TComMv(0,0), -1); + } + } + } +} + +/** search of the best candidate for inter prediction + * \param pcCU + * \param pcOrgYuv + * \param rpcPredYuv + * \param rpcResiYuv + * \param rpcRecoYuv + * \param bUseRes + * \returns Void + */ +#if AMP_MRG +Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG ) +#else +Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv, Bool bUseRes ) +#endif +{ + for(UInt i=0; iclear(); + + if ( !bUseRes ) + { + pcResiYuv->clear(); + } + + pcRecoYuv->clear(); + + TComMv cMvSrchRngLT; + TComMv cMvSrchRngRB; + + TComMv cMvZero; + TComMv TempMv; //kolya + + TComMv cMv[2]; + TComMv cMvBi[2]; + TComMv cMvTemp[2][33]; + + Int iNumPart = pcCU->getNumPartitions(); + Int iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2; + + TComMv cMvPred[2][33]; + + TComMv cMvPredBi[2][33]; + Int aaiMvpIdxBi[2][33]; + + Int aaiMvpIdx[2][33]; + Int aaiMvpNum[2][33]; + + AMVPInfo aacAMVPInfo[2][33]; + + Int iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage. + Int iRefIdxBi[2]; + + UInt uiPartAddr; + Int iRoiWidth, iRoiHeight; + + UInt uiMbBits[3] = {1, 1, 0}; + + UInt uiLastMode = 0; + Int iRefStart, iRefEnd; + + PartSize ePartSize = pcCU->getPartitionSize( 0 ); + + Int bestBiPRefIdxL1 = 0; + Int bestBiPMvpL1 = 0; + Distortion biPDistTemp = std::numeric_limits::max(); + + TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists + UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS]; + Int numValidMergeCand = 0 ; + + for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ) + { + Distortion uiCost[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; + Distortion uiCostBi = std::numeric_limits::max(); + Distortion uiCostTemp; + + UInt uiBits[3]; + UInt uiBitsTemp; + Distortion bestBiPDist = std::numeric_limits::max(); + + Distortion uiCostTempL0[MAX_NUM_REF]; + for (Int iNumRef=0; iNumRef < MAX_NUM_REF; iNumRef++) + { + uiCostTempL0[iNumRef] = std::numeric_limits::max(); + } + UInt uiBitsTempL0[MAX_NUM_REF]; + + TComMv mvValidList1; + Int refIdxValidList1 = 0; + UInt bitsValidList1 = MAX_UINT; + Distortion costValidList1 = std::numeric_limits::max(); + + xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits); + + pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); + +#if AMP_MRG + Bool bTestNormalMC = true; + + if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ) + { + bTestNormalMC = false; + } + + if (bTestNormalMC) + { +#endif + + // Uni-directional prediction + for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) + { + RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); + + for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) + { + uiBitsTemp = uiMbBits[iRefList]; + if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ) + { + uiBitsTemp += iRefIdxTemp+1; + if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) uiBitsTemp--; + } + xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp); + aaiMvpIdx[iRefList][iRefIdxTemp] = pcCU->getMVPIdx(eRefPicList, uiPartAddr); + aaiMvpNum[iRefList][iRefIdxTemp] = pcCU->getMVPNum(eRefPicList, uiPartAddr); + + if(pcCU->getSlice()->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist) + { + bestBiPDist = biPDistTemp; + bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp]; + bestBiPRefIdxL1 = iRefIdxTemp; + } + + uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; + +#if GPB_SIMPLE_UNI + if ( iRefList == 1 ) // list 1 + { + if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) + { + cMvTemp[1][iRefIdxTemp] = cMvTemp[0][pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )]; + uiCostTemp = uiCostTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )]; + /*first subtract the bit-rate part of the cost of the other list*/ + uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )] ); + /*correct the bit-rate part of the current ref*/ + m_pcRdCost->setPredictor ( cMvPred[iRefList][iRefIdxTemp] ); + uiBitsTemp += m_pcRdCost->getBits( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer() ); + /*calculate the correct cost*/ + uiCostTemp += m_pcRdCost->getCost( uiBitsTemp ); + } + else + { + xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + } + } + else + { + xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + } +#else + xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); +#endif + xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE ) + xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); + + if ( iRefList == 0 ) + { + uiCostTempL0[iRefIdxTemp] = uiCostTemp; + uiBitsTempL0[iRefIdxTemp] = uiBitsTemp; + } + if ( uiCostTemp < uiCost[iRefList] ) + { + uiCost[iRefList] = uiCostTemp; + uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction + + // set motion + cMv[iRefList] = cMvTemp[iRefList][iRefIdxTemp]; + iRefIdx[iRefList] = iRefIdxTemp; + } + + if ( iRefList == 1 && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ) + { + costValidList1 = uiCostTemp; + bitsValidList1 = uiBitsTemp; + + // set motion + mvValidList1 = cMvTemp[iRefList][iRefIdxTemp]; + refIdxValidList1 = iRefIdxTemp; + } + } + } + + // Bi-directional prediction + if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ) + { + + cMvBi[0] = cMv[0]; cMvBi[1] = cMv[1]; + iRefIdxBi[0] = iRefIdx[0]; iRefIdxBi[1] = iRefIdx[1]; + + ::memcpy(cMvPredBi, cMvPred, sizeof(cMvPred)); + ::memcpy(aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx)); + + UInt uiMotBits[2]; + + if(pcCU->getSlice()->getMvdL1ZeroFlag()) + { + xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()); + pcCU->setMVPIdxSubParts( bestBiPMvpL1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1; + cMvPredBi[1][bestBiPRefIdxL1] = pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()->m_acMvCand[bestBiPMvpL1]; + + cMvBi[1] = cMvPredBi[1][bestBiPRefIdxL1]; + iRefIdxBi[1] = bestBiPRefIdxL1; + pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx ); + TComYuv* pcYuvPred = &m_acYuvPred[REF_PIC_LIST_1]; + motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx ); + + uiMotBits[0] = uiBits[0] - uiMbBits[0]; + uiMotBits[1] = uiMbBits[1]; + + if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 ) + { + uiMotBits[1] += bestBiPRefIdxL1+1; + if ( bestBiPRefIdxL1 == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1 ) uiMotBits[1]--; + } + + uiMotBits[1] += m_auiMVPIdxCost[aaiMvpIdxBi[1][bestBiPRefIdxL1]][AMVP_MAX_NUM_CANDS]; + + uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1]; + + cMvTemp[1][bestBiPRefIdxL1] = cMvBi[1]; + } + else + { + uiMotBits[0] = uiBits[0] - uiMbBits[0]; + uiMotBits[1] = uiBits[1] - uiMbBits[1]; + uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1]; + } + + // 4-times iteration (default) + Int iNumIter = 4; + + // fast encoder setting: only one iteration + if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag()) + { + iNumIter = 1; + } + + for ( Int iIter = 0; iIter < iNumIter; iIter++ ) + { + Int iRefList = iIter % 2; + + if ( m_pcEncCfg->getUseFastEnc() ) + { + if( uiCost[0] <= uiCost[1] ) + { + iRefList = 1; + } + else + { + iRefList = 0; + } + } + else if ( iIter == 0 ) + { + iRefList = 0; + } + if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag()) + { + pcCU->getCUMvField(RefPicList(1-iRefList))->setAllMv( cMv[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(RefPicList(1-iRefList))->setAllRefIdx( iRefIdx[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx ); + TComYuv* pcYuvPred = &m_acYuvPred[1-iRefList]; + motionCompensation ( pcCU, pcYuvPred, RefPicList(1-iRefList), iPartIdx ); + } + + RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); + + if(pcCU->getSlice()->getMvdL1ZeroFlag()) + { + iRefList = 0; + eRefPicList = REF_PIC_LIST_0; + } + + Bool bChanged = false; + + iRefStart = 0; + iRefEnd = pcCU->getSlice()->getNumRefIdx(eRefPicList)-1; + + for ( Int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ ) + { + uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList]; + if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ) + { + uiBitsTemp += iRefIdxTemp+1; + if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) uiBitsTemp--; + } + uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; + // call ME + xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true ); + + xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo()); + xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); + + if ( uiCostTemp < uiCostBi ) + { + bChanged = true; + + cMvBi[iRefList] = cMvTemp[iRefList][iRefIdxTemp]; + iRefIdxBi[iRefList] = iRefIdxTemp; + + uiCostBi = uiCostTemp; + uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList]; + uiBits[2] = uiBitsTemp; + + if(iNumIter!=1) + { + // Set motion + pcCU->getCUMvField( eRefPicList )->setAllMv( cMvBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField( eRefPicList )->setAllRefIdx( iRefIdxBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx ); + + TComYuv* pcYuvPred = &m_acYuvPred[iRefList]; + motionCompensation( pcCU, pcYuvPred, eRefPicList, iPartIdx ); + } + } + } // for loop-iRefIdxTemp + + if ( !bChanged ) + { + if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) + { + xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], pcCU->getCUMvField(REF_PIC_LIST_0)->getAMVPInfo()); + xCheckBestMVP(pcCU, REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi); + if(!pcCU->getSlice()->getMvdL1ZeroFlag()) + { + xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()); + xCheckBestMVP(pcCU, REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], uiBits[2], uiCostBi); + } + } + break; + } + } // for loop-iter + } // if (B_SLICE) + +#if AMP_MRG + } //end if bTestNormalMC +#endif + // Clear Motion Field + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + + UInt uiMEBits = 0; + // Set Motion Field_ + cMv[1] = mvValidList1; + iRefIdx[1] = refIdxValidList1; + uiBits[1] = bitsValidList1; + uiCost[1] = costValidList1; + +#if AMP_MRG + if (bTestNormalMC) + { +#endif + if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) + { + uiLastMode = 2; + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMvBi[0], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdxBi[0], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx ); + + TempMv = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]]; + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx ); + + TempMv = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]]; + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) ); + + pcCU->setMVPIdxSubParts( aaiMvpIdxBi[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPIdxSubParts( aaiMvpIdxBi[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + + uiMEBits = uiBits[2]; + } + else if ( uiCost[0] <= uiCost[1] ) + { + uiLastMode = 0; + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMv[0], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdx[0], ePartSize, uiPartAddr, 0, iPartIdx ); + + TempMv = cMv[0] - cMvPred[0][iRefIdx[0]]; + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) ); + + pcCU->setMVPIdxSubParts( aaiMvpIdx[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + + uiMEBits = uiBits[0]; + } + else + { + uiLastMode = 1; + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMv[1], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdx[1], ePartSize, uiPartAddr, 0, iPartIdx ); + + TempMv = cMv[1] - cMvPred[1][iRefIdx[1]]; + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) ); + + pcCU->setMVPIdxSubParts( aaiMvpIdx[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + + uiMEBits = uiBits[1]; + } +#if AMP_MRG + } // end if bTestNormalMC +#endif + + if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N ) + { + UInt uiMRGInterDir = 0; + TComMvField cMRGMvField[2]; + UInt uiMRGIndex = 0; + + UInt uiMEInterDir = 0; + TComMvField cMEMvField[2]; + + m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) ); + +#if AMP_MRG + // calculate ME cost + Distortion uiMEError = std::numeric_limits::max(); + Distortion uiMECost = std::numeric_limits::max(); + + if (bTestNormalMC) + { + xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() ); + uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits ); + } +#else + // calculate ME cost + Distortion uiMEError = std::numeric_limits::max(); + xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() ); + Distortion uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits ); +#endif + // save ME result. + uiMEInterDir = pcCU->getInterDir( uiPartAddr ); + pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_0, cMEMvField[0] ); + pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[1] ); + + // find Merge result + Distortion uiMRGCost = std::numeric_limits::max(); + + xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand); + + if ( uiMRGCost < uiMECost ) + { + // set Merge result + pcCU->setMergeFlagSubParts ( true, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) ); + pcCU->setMergeIndexSubParts( uiMRGIndex, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) ); + pcCU->setInterDirSubParts ( uiMRGInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) ); + pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMRGMvField[0], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMRGMvField[1], ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx ); + + pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); + } + else + { + // set ME result + pcCU->setMergeFlagSubParts( false, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) ); + pcCU->setInterDirSubParts ( uiMEInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) ); + pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMEMvField[0], ePartSize, uiPartAddr, 0, iPartIdx ); + pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[1], ePartSize, uiPartAddr, 0, iPartIdx ); + } + } + + // MC + motionCompensation ( pcCU, pcPredYuv, REF_PIC_LIST_X, iPartIdx ); + + } // end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ) + + setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X ); + + return; +} + + +// AMVP +Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP ) +{ + AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo(); + + TComMv cBestMv; + Int iBestIdx = 0; + TComMv cZeroMv; + TComMv cMvPred; + Distortion uiBestCost = std::numeric_limits::max(); + UInt uiPartAddr = 0; + Int iRoiWidth, iRoiHeight; + Int i; + + pcCU->getPartIndexAndSize( uiPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); + // Fill the MV Candidates + if (!bFilled) + { + pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, pcAMVPInfo ); + } + + // initialize Mvp index & Mvp + iBestIdx = 0; + cBestMv = pcAMVPInfo->m_acMvCand[0]; + if (pcAMVPInfo->iN <= 1) + { + rcMvPred = cBestMv; + + pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + + if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefPicList==REF_PIC_LIST_1) + { + (*puiDistBiP) = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight); + } + return; + } + + if (bFilled) + { + assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0); + rcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)]; + return; + } + + m_cYuvPredTemp.clear(); + //-- Check Minimum Cost. + for ( i = 0 ; i < pcAMVPInfo->iN; i++) + { + Distortion uiTmpCost; + uiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight); + if ( uiBestCost > uiTmpCost ) + { + uiBestCost = uiTmpCost; + cBestMv = pcAMVPInfo->m_acMvCand[i]; + iBestIdx = i; + (*puiDistBiP) = uiTmpCost; + } + } + + m_cYuvPredTemp.clear(); + + // Setting Best MVP + rcMvPred = cBestMv; + pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); + return; +} + +UInt TEncSearch::xGetMvpIdxBits(Int iIdx, Int iNum) +{ + assert(iIdx >= 0 && iNum >= 0 && iIdx < iNum); + + if (iNum == 1) + { + return 0; + } + + UInt uiLength = 1; + Int iTemp = iIdx; + if ( iTemp == 0 ) + { + return uiLength; + } + + Bool bCodeLast = ( iNum-1 > iTemp ); + + uiLength += (iTemp-1); + + if( bCodeLast ) + { + uiLength++; + } + + return uiLength; +} + +Void TEncSearch::xGetBlkBits( PartSize eCUMode, Bool bPSlice, Int iPartIdx, UInt uiLastMode, UInt uiBlkBit[3]) +{ + if ( eCUMode == SIZE_2Nx2N ) + { + uiBlkBit[0] = (! bPSlice) ? 3 : 1; + uiBlkBit[1] = 3; + uiBlkBit[2] = 5; + } + else if ( (eCUMode == SIZE_2NxN || eCUMode == SIZE_2NxnU) || eCUMode == SIZE_2NxnD ) + { + UInt aauiMbBits[2][3][3] = { { {0,0,3}, {0,0,0}, {0,0,0} } , { {5,7,7}, {7,5,7}, {9-3,9-3,9-3} } }; + if ( bPSlice ) + { + uiBlkBit[0] = 3; + uiBlkBit[1] = 0; + uiBlkBit[2] = 0; + } + else + { + ::memcpy( uiBlkBit, aauiMbBits[iPartIdx][uiLastMode], 3*sizeof(UInt) ); + } + } + else if ( (eCUMode == SIZE_Nx2N || eCUMode == SIZE_nLx2N) || eCUMode == SIZE_nRx2N ) + { + UInt aauiMbBits[2][3][3] = { { {0,2,3}, {0,0,0}, {0,0,0} } , { {5,7,7}, {7-2,7-2,9-2}, {9-3,9-3,9-3} } }; + if ( bPSlice ) + { + uiBlkBit[0] = 3; + uiBlkBit[1] = 0; + uiBlkBit[2] = 0; + } + else + { + ::memcpy( uiBlkBit, aauiMbBits[iPartIdx][uiLastMode], 3*sizeof(UInt) ); + } + } + else if ( eCUMode == SIZE_NxN ) + { + uiBlkBit[0] = (! bPSlice) ? 3 : 1; + uiBlkBit[1] = 3; + uiBlkBit[2] = 5; + } + else + { + printf("Wrong!\n"); + assert( 0 ); + } +} + +Void TEncSearch::xCopyAMVPInfo (AMVPInfo* pSrc, AMVPInfo* pDst) +{ + pDst->iN = pSrc->iN; + for (Int i = 0; i < pSrc->iN; i++) + { + pDst->m_acMvCand[i] = pSrc->m_acMvCand[i]; + } +} + +Void TEncSearch::xCheckBestMVP ( TComDataCU* pcCU, RefPicList eRefPicList, TComMv cMv, TComMv& rcMvPred, Int& riMVPIdx, UInt& ruiBits, Distortion& ruiCost ) +{ + AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo(); + + assert(pcAMVPInfo->m_acMvCand[riMVPIdx] == rcMvPred); + + if (pcAMVPInfo->iN < 2) return; + + m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(0) ); + m_pcRdCost->setCostScale ( 0 ); + + Int iBestMVPIdx = riMVPIdx; + + m_pcRdCost->setPredictor( rcMvPred ); + Int iOrgMvBits = m_pcRdCost->getBits(cMv.getHor(), cMv.getVer()); + iOrgMvBits += m_auiMVPIdxCost[riMVPIdx][AMVP_MAX_NUM_CANDS]; + Int iBestMvBits = iOrgMvBits; + + for (Int iMVPIdx = 0; iMVPIdx < pcAMVPInfo->iN; iMVPIdx++) + { + if (iMVPIdx == riMVPIdx) continue; + + m_pcRdCost->setPredictor( pcAMVPInfo->m_acMvCand[iMVPIdx] ); + + Int iMvBits = m_pcRdCost->getBits(cMv.getHor(), cMv.getVer()); + iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS]; + + if (iMvBits < iBestMvBits) + { + iBestMvBits = iMvBits; + iBestMVPIdx = iMVPIdx; + } + } + + if (iBestMVPIdx != riMVPIdx) //if changed + { + rcMvPred = pcAMVPInfo->m_acMvCand[iBestMVPIdx]; + + riMVPIdx = iBestMVPIdx; + UInt uiOrgBits = ruiBits; + ruiBits = uiOrgBits - iOrgMvBits + iBestMvBits; + ruiCost = (ruiCost - m_pcRdCost->getCost( uiOrgBits )) + m_pcRdCost->getCost( ruiBits ); + } +} + + +Distortion TEncSearch::xGetTemplateCost( TComDataCU* pcCU, + UInt uiPartIdx, + UInt uiPartAddr, + TComYuv* pcOrgYuv, + TComYuv* pcTemplateCand, + TComMv cMvCand, + Int iMVPIdx, + Int iMVPNum, + RefPicList eRefPicList, + Int iRefIdx, + Int iSizeX, + Int iSizeY + ) +{ + Distortion uiCost = std::numeric_limits::max(); + + TComPicYuv* pcPicYuvRef = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdx )->getPicYuvRec(); + + pcCU->clipMv( cMvCand ); + + // prediction pattern + if ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType()==P_SLICE ) + { + xPredInterBlk( COMPONENT_Y, pcCU, pcPicYuvRef, uiPartAddr, &cMvCand, iSizeX, iSizeY, pcTemplateCand, true ); + } + else + { + xPredInterBlk( COMPONENT_Y, pcCU, pcPicYuvRef, uiPartAddr, &cMvCand, iSizeX, iSizeY, pcTemplateCand, false ); + } + + if ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType()==P_SLICE ) + { + xWeightedPredictionUni( pcCU, pcTemplateCand, uiPartAddr, iSizeX, iSizeY, eRefPicList, pcTemplateCand, iRefIdx ); + } + + // calc distortion + + uiCost = m_pcRdCost->getDistPart( g_bitDepth[CHANNEL_TYPE_LUMA], pcTemplateCand->getAddr(COMPONENT_Y, uiPartAddr), pcTemplateCand->getStride(COMPONENT_Y), pcOrgYuv->getAddr(COMPONENT_Y, uiPartAddr), pcOrgYuv->getStride(COMPONENT_Y), iSizeX, iSizeY, COMPONENT_Y, DF_SAD ); + uiCost = (UInt) m_pcRdCost->calcRdCost( m_auiMVPIdxCost[iMVPIdx][iMVPNum], uiCost, false, DF_SAD ); + return uiCost; +} + + + + +Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, Distortion& ruiCost, Bool bBi ) +{ + UInt uiPartAddr; + Int iRoiWidth; + Int iRoiHeight; + + TComMv cMvHalf, cMvQter; + TComMv cMvSrchRngLT; + TComMv cMvSrchRngRB; + + TComYuv* pcYuv = pcYuvOrg; + + assert(eRefPicList < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdxPredgetPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); + + if ( bBi ) + { + TComYuv* pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList]; + pcYuv = &m_cYuvPredTemp; + + pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight ); + + pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight ); + + fWeight = 0.5; + } + + // Search key pattern initialization + pcPatternKey->initPattern( pcYuv->getAddr ( COMPONENT_Y, uiPartAddr ), + iRoiWidth, + iRoiHeight, + pcYuv->getStride(COMPONENT_Y) ); + + Pel* piRefY = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu() + uiPartAddr ); + Int iRefStride = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride(COMPONENT_Y); + + TComMv cMvPred = *pcMvPred; + + if ( bBi ) xSetSearchRange ( pcCU, rcMv , iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); + else xSetSearchRange ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); + + m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) ); + + m_pcRdCost->setPredictor ( *pcMvPred ); + m_pcRdCost->setCostScale ( 2 ); + + setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList ); + // Do integer search + if ( !m_iFastSearch || bBi ) + { + xPatternSearch ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost ); + } + else + { + rcMv = *pcMvPred; + const TComMv *pIntegerMv2Nx2NPred=0; + if (pcCU->getPartitionSize(0) != SIZE_2Nx2N || pcCU->getDepth(0) != 0) + { + pIntegerMv2Nx2NPred = &(m_integerMv2Nx2N[eRefPicList][iRefIdxPred]); + } + xPatternSearchFast ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost, pIntegerMv2Nx2NPred ); + if (pcCU->getPartitionSize(0) == SIZE_2Nx2N) + { + m_integerMv2Nx2N[eRefPicList][iRefIdxPred] = rcMv; + } + } + + m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) ); + m_pcRdCost->setCostScale ( 1 ); + + const Bool bIsLosslessCoded = pcCU->getCUTransquantBypass(uiPartAddr) != 0; + xPatternSearchFracDIF( bIsLosslessCoded, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost ,bBi ); + + m_pcRdCost->setCostScale( 0 ); + rcMv <<= 2; + rcMv += (cMvHalf <<= 1); + rcMv += cMvQter; + + UInt uiMvBits = m_pcRdCost->getBits( rcMv.getHor(), rcMv.getVer() ); + + ruiBits += uiMvBits; + ruiCost = (Distortion)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) ); +} + + + + +Void TEncSearch::xSetSearchRange ( TComDataCU* pcCU, TComMv& cMvPred, Int iSrchRng, TComMv& rcMvSrchRngLT, TComMv& rcMvSrchRngRB ) +{ + Int iMvShift = 2; + TComMv cTmpMvPred = cMvPred; + pcCU->clipMv( cTmpMvPred ); + + rcMvSrchRngLT.setHor( cTmpMvPred.getHor() - (iSrchRng << iMvShift) ); + rcMvSrchRngLT.setVer( cTmpMvPred.getVer() - (iSrchRng << iMvShift) ); + + rcMvSrchRngRB.setHor( cTmpMvPred.getHor() + (iSrchRng << iMvShift) ); + rcMvSrchRngRB.setVer( cTmpMvPred.getVer() + (iSrchRng << iMvShift) ); + pcCU->clipMv ( rcMvSrchRngLT ); + pcCU->clipMv ( rcMvSrchRngRB ); + + rcMvSrchRngLT >>= iMvShift; + rcMvSrchRngRB >>= iMvShift; +} + + + + +Void TEncSearch::xPatternSearch( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, TComMv& rcMv, Distortion& ruiSAD ) +{ + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + + Distortion uiSad; + Distortion uiSadBest = std::numeric_limits::max(); + Int iBestX = 0; + Int iBestY = 0; + + Pel* piRefSrch; + + //-- jclee for using the SAD function pointer + m_pcRdCost->setDistParam( pcPatternKey, piRefY, iRefStride, m_cDistParam ); + + // fast encoder decision: use subsampled SAD for integer ME + if ( m_pcEncCfg->getUseFastEnc() ) + { + if ( m_cDistParam.iRows > 8 ) + { + m_cDistParam.iSubShift = 1; + } + } + + piRefY += (iSrchRngVerTop * iRefStride); + for ( Int y = iSrchRngVerTop; y <= iSrchRngVerBottom; y++ ) + { + for ( Int x = iSrchRngHorLeft; x <= iSrchRngHorRight; x++ ) + { + // find min. distortion position + piRefSrch = piRefY + x; + m_cDistParam.pCur = piRefSrch; + + setDistParamComp(COMPONENT_Y); + + m_cDistParam.bitDepth = g_bitDepth[CHANNEL_TYPE_LUMA]; + uiSad = m_cDistParam.DistFunc( &m_cDistParam ); + + // motion cost + uiSad += m_pcRdCost->getCost( x, y ); + + if ( uiSad < uiSadBest ) + { + uiSadBest = uiSad; + iBestX = x; + iBestY = y; + } + } + piRefY += iRefStride; + } + + rcMv.set( iBestX, iBestY ); + + ruiSAD = uiSadBest - m_pcRdCost->getCost( iBestX, iBestY ); + return; +} + + + +Void TEncSearch::xPatternSearchFast( TComDataCU* pcCU, + TComPattern* pcPatternKey, + Pel* piRefY, + Int iRefStride, + TComMv* pcMvSrchRngLT, + TComMv* pcMvSrchRngRB, + TComMv &rcMv, + Distortion &ruiSAD, + const TComMv* pIntegerMv2Nx2NPred ) +{ + assert (MD_LEFT < NUM_MV_PREDICTORS); + pcCU->getMvPredLeft ( m_acMvPredictors[MD_LEFT] ); + assert (MD_ABOVE < NUM_MV_PREDICTORS); + pcCU->getMvPredAbove ( m_acMvPredictors[MD_ABOVE] ); + assert (MD_ABOVE_RIGHT < NUM_MV_PREDICTORS); + pcCU->getMvPredAboveRight ( m_acMvPredictors[MD_ABOVE_RIGHT] ); + + switch ( m_iFastSearch ) + { + case 1: + xTZSearch( pcCU, pcPatternKey, piRefY, iRefStride, pcMvSrchRngLT, pcMvSrchRngRB, rcMv, ruiSAD, pIntegerMv2Nx2NPred ); + break; + + case 2: + xTZSearchSelective( pcCU, pcPatternKey, piRefY, iRefStride, pcMvSrchRngLT, pcMvSrchRngRB, rcMv, ruiSAD, pIntegerMv2Nx2NPred ); + break; + default: + break; + } +} + + + + +Void TEncSearch::xTZSearch( TComDataCU* pcCU, + TComPattern* pcPatternKey, + Pel* piRefY, + Int iRefStride, + TComMv* pcMvSrchRngLT, + TComMv* pcMvSrchRngRB, + TComMv &rcMv, + Distortion &ruiSAD, + const TComMv* pIntegerMv2Nx2NPred ) +{ + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + + TZ_SEARCH_CONFIGURATION + + UInt uiSearchRange = m_iSearchRange; + pcCU->clipMv( rcMv ); + rcMv >>= 2; + // init TZSearchStruct + IntTZSearchStruct cStruct; + cStruct.iYStride = iRefStride; + cStruct.piRefY = piRefY; + cStruct.uiBestSad = MAX_UINT; + + // set rcMv (Median predictor) as start point and as best point + xTZSearchHelp( pcPatternKey, cStruct, rcMv.getHor(), rcMv.getVer(), 0, 0 ); + + // test whether one of PRED_A, PRED_B, PRED_C MV is better start point than Median predictor + if ( bTestOtherPredictedMV ) + { + for ( UInt index = 0; index < NUM_MV_PREDICTORS; index++ ) + { + TComMv cMv = m_acMvPredictors[index]; + pcCU->clipMv( cMv ); + cMv >>= 2; + xTZSearchHelp( pcPatternKey, cStruct, cMv.getHor(), cMv.getVer(), 0, 0 ); + } + } + + // test whether zero Mv is better start point than Median predictor + if ( bTestZeroVector ) + { + xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 ); + } + + if (pIntegerMv2Nx2NPred != 0) + { + TComMv integerMv2Nx2NPred = *pIntegerMv2Nx2NPred; + integerMv2Nx2NPred <<= 2; + pcCU->clipMv( integerMv2Nx2NPred ); + integerMv2Nx2NPred >>= 2; + xTZSearchHelp(pcPatternKey, cStruct, integerMv2Nx2NPred.getHor(), integerMv2Nx2NPred.getVer(), 0, 0); + + // reset search range + TComMv cMvSrchRngLT; + TComMv cMvSrchRngRB; + Int iSrchRng = m_iSearchRange; + TComMv currBestMv(cStruct.iBestX, cStruct.iBestY ); + currBestMv <<= 2; + xSetSearchRange( pcCU, currBestMv, iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); + iSrchRngHorLeft = cMvSrchRngLT.getHor(); + iSrchRngHorRight = cMvSrchRngRB.getHor(); + iSrchRngVerTop = cMvSrchRngLT.getVer(); + iSrchRngVerBottom = cMvSrchRngRB.getVer(); + } + + // start search + Int iDist = 0; + Int iStartX = cStruct.iBestX; + Int iStartY = cStruct.iBestY; + + // first search + for ( iDist = 1; iDist <= (Int)uiSearchRange; iDist*=2 ) + { + if ( bFirstSearchDiamond == 1 ) + { + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + else + { + xTZ8PointSquareSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + + if ( bFirstSearchStop && ( cStruct.uiBestRound >= uiFirstSearchRounds ) ) // stop criterion + { + break; + } + } + + // test whether zero Mv is a better start point than Median predictor + if ( bTestZeroVectorStart && ((cStruct.iBestX != 0) || (cStruct.iBestY != 0)) ) + { + xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 ); + if ( (cStruct.iBestX == 0) && (cStruct.iBestY == 0) ) + { + // test its neighborhood + for ( iDist = 1; iDist <= (Int)uiSearchRange; iDist*=2 ) + { + xTZ8PointDiamondSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, 0, 0, iDist ); + if ( bTestZeroVectorStop && (cStruct.uiBestRound > 0) ) // stop criterion + { + break; + } + } + } + } + + // calculate only 2 missing points instead 8 points if cStruct.uiBestDistance == 1 + if ( cStruct.uiBestDistance == 1 ) + { + cStruct.uiBestDistance = 0; + xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB ); + } + + // raster search if distance is too big + if ( bEnableRasterSearch && ( ((Int)(cStruct.uiBestDistance) > iRaster) || bAlwaysRasterSearch ) ) + { + cStruct.uiBestDistance = iRaster; + for ( iStartY = iSrchRngVerTop; iStartY <= iSrchRngVerBottom; iStartY += iRaster ) + { + for ( iStartX = iSrchRngHorLeft; iStartX <= iSrchRngHorRight; iStartX += iRaster ) + { + xTZSearchHelp( pcPatternKey, cStruct, iStartX, iStartY, 0, iRaster ); + } + } + } + + // raster refinement + if ( bRasterRefinementEnable && cStruct.uiBestDistance > 0 ) + { + while ( cStruct.uiBestDistance > 0 ) + { + iStartX = cStruct.iBestX; + iStartY = cStruct.iBestY; + if ( cStruct.uiBestDistance > 1 ) + { + iDist = cStruct.uiBestDistance >>= 1; + if ( bRasterRefinementDiamond == 1 ) + { + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + else + { + xTZ8PointSquareSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + } + + // calculate only 2 missing points instead 8 points if cStruct.uiBestDistance == 1 + if ( cStruct.uiBestDistance == 1 ) + { + cStruct.uiBestDistance = 0; + if ( cStruct.ucPointNr != 0 ) + { + xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB ); + } + } + } + } + + // start refinement + if ( bStarRefinementEnable && cStruct.uiBestDistance > 0 ) + { + while ( cStruct.uiBestDistance > 0 ) + { + iStartX = cStruct.iBestX; + iStartY = cStruct.iBestY; + cStruct.uiBestDistance = 0; + cStruct.ucPointNr = 0; + for ( iDist = 1; iDist < (Int)uiSearchRange + 1; iDist*=2 ) + { + if ( bStarRefinementDiamond == 1 ) + { + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + else + { + xTZ8PointSquareSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + if ( bStarRefinementStop && (cStruct.uiBestRound >= uiStarRefinementRounds) ) // stop criterion + { + break; + } + } + + // calculate only 2 missing points instead 8 points if cStrukt.uiBestDistance == 1 + if ( cStruct.uiBestDistance == 1 ) + { + cStruct.uiBestDistance = 0; + if ( cStruct.ucPointNr != 0 ) + { + xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB ); + } + } + } + } + + // write out best match + rcMv.set( cStruct.iBestX, cStruct.iBestY ); + ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCost( cStruct.iBestX, cStruct.iBestY ); +} + + +Void TEncSearch::xTZSearchSelective( TComDataCU* pcCU, + TComPattern* pcPatternKey, + Pel* piRefY, + Int iRefStride, + TComMv* pcMvSrchRngLT, + TComMv* pcMvSrchRngRB, + TComMv &rcMv, + Distortion &ruiSAD, + const TComMv* pIntegerMv2Nx2NPred ) +{ + SEL_SEARCH_CONFIGURATION + + Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); + Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); + Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); + Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); + Int iFirstSrchRngHorLeft = 0; + Int iFirstSrchRngHorRight = 0; + Int iFirstSrchRngVerTop = 0; + Int iFirstSrchRngVerBottom = 0; + Int iStartX = 0; + Int iStartY = 0; + Int iBestX = 0; + Int iBestY = 0; + Int iDist = 0; + + pcCU->clipMv( rcMv ); + rcMv >>= 2; + // init TZSearchStruct + IntTZSearchStruct cStruct; + cStruct.iYStride = iRefStride; + cStruct.piRefY = piRefY; + cStruct.uiBestSad = MAX_UINT; + cStruct.iBestX = 0; + cStruct.iBestY = 0; + + + // set rcMv (Median predictor) as start point and as best point + xTZSearchHelp( pcPatternKey, cStruct, rcMv.getHor(), rcMv.getVer(), 0, 0 ); + + // test whether one of PRED_A, PRED_B, PRED_C MV is better start point than Median predictor + if ( bTestOtherPredictedMV ) + { + for ( UInt index = 0; index < NUM_MV_PREDICTORS; index++ ) + { + TComMv cMv = m_acMvPredictors[index]; + pcCU->clipMv( cMv ); + cMv >>= 2; + xTZSearchHelp( pcPatternKey, cStruct, cMv.getHor(), cMv.getVer(), 0, 0 ); + } + } + + // test whether zero Mv is better start point than Median predictor + if ( bTestZeroVector ) + { + xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 ); + } + + if ( pIntegerMv2Nx2NPred != 0 ) + { + TComMv integerMv2Nx2NPred = *pIntegerMv2Nx2NPred; + integerMv2Nx2NPred <<= 2; + pcCU->clipMv( integerMv2Nx2NPred ); + integerMv2Nx2NPred >>= 2; + xTZSearchHelp(pcPatternKey, cStruct, integerMv2Nx2NPred.getHor(), integerMv2Nx2NPred.getVer(), 0, 0); + + // reset search range + TComMv cMvSrchRngLT; + TComMv cMvSrchRngRB; + Int iSrchRng = m_iSearchRange; + TComMv currBestMv(cStruct.iBestX, cStruct.iBestY ); + currBestMv <<= 2; + xSetSearchRange( pcCU, currBestMv, iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); + iSrchRngHorLeft = cMvSrchRngLT.getHor(); + iSrchRngHorRight = cMvSrchRngRB.getHor(); + iSrchRngVerTop = cMvSrchRngLT.getVer(); + iSrchRngVerBottom = cMvSrchRngRB.getVer(); + } + + // Initial search + iBestX = cStruct.iBestX; + iBestY = cStruct.iBestY; + iFirstSrchRngHorLeft = ((iBestX - uiSearchRangeInitial) > iSrchRngHorLeft) ? (iBestX - uiSearchRangeInitial) : iSrchRngHorLeft; + iFirstSrchRngVerTop = ((iBestY - uiSearchRangeInitial) > iSrchRngVerTop) ? (iBestY - uiSearchRangeInitial) : iSrchRngVerTop; + iFirstSrchRngHorRight = ((iBestX + uiSearchRangeInitial) < iSrchRngHorRight) ? (iBestX + uiSearchRangeInitial) : iSrchRngHorRight; + iFirstSrchRngVerBottom = ((iBestY + uiSearchRangeInitial) < iSrchRngVerBottom) ? (iBestY + uiSearchRangeInitial) : iSrchRngVerBottom; + + for ( iStartY = iFirstSrchRngVerTop; iStartY <= iFirstSrchRngVerBottom; iStartY += uiSearchStep ) + { + for ( iStartX = iFirstSrchRngHorLeft; iStartX <= iFirstSrchRngHorRight; iStartX += uiSearchStep ) + { + xTZSearchHelp( pcPatternKey, cStruct, iStartX, iStartY, 0, 0 ); + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, 1 ); + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, 2 ); + } + } + + Int iMaxMVDistToPred = (abs(cStruct.iBestX - iBestX) > iMVDistThresh || abs(cStruct.iBestY - iBestY) > iMVDistThresh); + + //full search with early exit if MV is distant from predictors + if ( bEnableRasterSearch && (iMaxMVDistToPred || bAlwaysRasterSearch) ) + { + for ( iStartY = iSrchRngVerTop; iStartY <= iSrchRngVerBottom; iStartY += 1 ) + { + for ( iStartX = iSrchRngHorLeft; iStartX <= iSrchRngHorRight; iStartX += 1 ) + { + xTZSearchHelp( pcPatternKey, cStruct, iStartX, iStartY, 0, 1 ); + } + } + } + //Smaller MV, refine around predictor + else if ( bStarRefinementEnable && cStruct.uiBestDistance > 0 ) + { + // start refinement + while ( cStruct.uiBestDistance > 0 ) + { + iStartX = cStruct.iBestX; + iStartY = cStruct.iBestY; + cStruct.uiBestDistance = 0; + cStruct.ucPointNr = 0; + for ( iDist = 1; iDist < (Int)uiSearchRange + 1; iDist*=2 ) + { + if ( bStarRefinementDiamond == 1 ) + { + xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + else + { + xTZ8PointSquareSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); + } + if ( bStarRefinementStop && (cStruct.uiBestRound >= uiStarRefinementRounds) ) // stop criterion + { + break; + } + } + + // calculate only 2 missing points instead 8 points if cStrukt.uiBestDistance == 1 + if ( cStruct.uiBestDistance == 1 ) + { + cStruct.uiBestDistance = 0; + if ( cStruct.ucPointNr != 0 ) + { + xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB ); + } + } + } + } + + // write out best match + rcMv.set( cStruct.iBestX, cStruct.iBestY ); + ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCost( cStruct.iBestX, cStruct.iBestY ); + +} + + +Void TEncSearch::xPatternSearchFracDIF( + Bool bIsLosslessCoded, + TComPattern* pcPatternKey, + Pel* piRefY, + Int iRefStride, + TComMv* pcMvInt, + TComMv& rcMvHalf, + TComMv& rcMvQter, + Distortion& ruiCost, + Bool biPred + ) +{ + // Reference pattern initialization (integer scale) + TComPattern cPatternRoi; + Int iOffset = pcMvInt->getHor() + pcMvInt->getVer() * iRefStride; + cPatternRoi.initPattern(piRefY + iOffset, + pcPatternKey->getROIYWidth(), + pcPatternKey->getROIYHeight(), + iRefStride ); + + // Half-pel refinement + xExtDIFUpSamplingH ( &cPatternRoi, biPred ); + + rcMvHalf = *pcMvInt; rcMvHalf <<= 1; // for mv-cost + TComMv baseRefMv(0, 0); + ruiCost = xPatternRefinement( pcPatternKey, baseRefMv, 2, rcMvHalf, !bIsLosslessCoded ); + + m_pcRdCost->setCostScale( 0 ); + + xExtDIFUpSamplingQ ( &cPatternRoi, rcMvHalf, biPred ); + baseRefMv = rcMvHalf; + baseRefMv <<= 1; + + rcMvQter = *pcMvInt; rcMvQter <<= 1; // for mv-cost + rcMvQter += rcMvHalf; rcMvQter <<= 1; + ruiCost = xPatternRefinement( pcPatternKey, baseRefMv, 1, rcMvQter, !bIsLosslessCoded ); +} + + +/** encode residual and calculate rate-distortion for a CU block + * \param pcCU + * \param pcYuvOrg + * \param pcYuvPred + * \param rpcYuvResi + * \param rpcYuvResiBest + * \param rpcYuvRec + * \param bSkipRes + * \returns Void + */ +Void TEncSearch::encodeResAndCalcRdInterCU( TComDataCU* pcCU, TComYuv* pcYuvOrg, TComYuv* pcYuvPred, + TComYuv* pcYuvResi, TComYuv* pcYuvResiBest, TComYuv* pcYuvRec, + Bool bSkipRes DEBUG_STRING_FN_DECLARE(sDebug) ) +{ + if ( pcCU->isIntra(0) ) + { + return; + } + + Bool bHighPass = pcCU->getSlice()->getDepth() ? true : false; + UInt uiBits = 0, uiBitsBest = 0; + Distortion uiDistortion = 0, uiDistortionBest = 0; + + UInt uiWidth = pcCU->getWidth ( 0 ); + UInt uiHeight = pcCU->getHeight( 0 ); + + // No residual coding : SKIP mode + if ( bSkipRes ) + { + pcCU->setSkipFlagSubParts( true, 0, pcCU->getDepth(0) ); + + pcYuvResi->clear(); + + pcYuvPred->copyToPartYuv( pcYuvRec, 0 ); + + for (UInt ch=0; ch < pcCU->getPic()->getNumberValidComponents(); ch++) + { + const ComponentID compID=ComponentID(ch); + const UInt csx=pcYuvOrg->getComponentScaleX(compID); + const UInt csy=pcYuvOrg->getComponentScaleY(compID); + uiDistortion += m_pcRdCost->getDistPart( g_bitDepth[toChannelType(compID)], pcYuvRec->getAddr(compID), pcYuvRec->getStride(compID), pcYuvOrg->getAddr(compID), + pcYuvOrg->getStride(compID), uiWidth >> csx, uiHeight >> csy, compID); + } + + m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_CURR_BEST]); + m_pcEntropyCoder->resetBits(); + + if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag(pcCU, 0, true); + } + + m_pcEntropyCoder->encodeSkipFlag(pcCU, 0, true); + m_pcEntropyCoder->encodeMergeIndex( pcCU, 0, true ); + + uiBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + pcCU->getTotalBits() = uiBits; + pcCU->getTotalDistortion() = uiDistortion; + pcCU->getTotalCost() = m_pcRdCost->calcRdCost( uiBits, uiDistortion ); + + m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_TEMP_BEST]); + + static const UInt cbfZero[MAX_NUM_COMPONENT]={0,0,0}; + pcCU->setCbfSubParts( cbfZero, 0, pcCU->getDepth( 0 ) ); + pcCU->setTrIdxSubParts( 0, 0, pcCU->getDepth(0) ); + +#ifdef DEBUG_STRING + pcYuvResiBest->clear(); // Clear the residual image, if we didn't code it. + for(UInt i=0; igetWidth(0) > pcCU->getSlice()->getSPS()->getMaxTrSize()) ) + { + while( pcCU->getWidth(0) > (pcCU->getSlice()->getSPS()->getMaxTrSize()<getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, pcCU->getQP(0) - m_iMaxDeltaQP ) : pcCU->getQP( 0 ); + qpMax = bHighPass ? Clip3( -pcCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, pcCU->getQP(0) + m_iMaxDeltaQP ) : pcCU->getQP( 0 ); + + pcYuvResi->subtract( pcYuvOrg, pcYuvPred, 0, uiWidth ); + + TComTURecurse tuLevel0(pcCU, 0); + + for ( qp = qpMin; qp <= qpMax; qp++ ) + { + dCost = 0.; + uiBits = 0; + uiDistortion = 0; + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_CURR_BEST ] ); + + Distortion uiZeroDistortion = 0; + + xEstimateResidualQT( pcYuvResi, dCost, uiBits, uiDistortion, &uiZeroDistortion, tuLevel0 DEBUG_STRING_PASS_INTO(sDebug) ); + + // ------------------------------------------------------- + // set the coefficients in the pcCU, and also calculates the residual data. + // If a block full of 0's is efficient, then just use 0's. + // The costs at this point do not include header bits. + + m_pcEntropyCoder->resetBits(); + m_pcEntropyCoder->encodeQtRootCbfZero( pcCU ); + UInt zeroResiBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + Double dZeroCost = m_pcRdCost->calcRdCost( zeroResiBits, uiZeroDistortion ); + + if(pcCU->isLosslessCoded( 0 )) + { + dZeroCost = dCost + 1; + } + + if ( dZeroCost < dCost ) + { + if ( dZeroCost < dCost ) + { + dCost = dZeroCost; + } + uiDistortion = uiZeroDistortion; + + const UInt uiQPartNum = tuLevel0.GetAbsPartIdxNumParts(); + ::memset( pcCU->getTransformIdx() , 0, uiQPartNum * sizeof(UChar) ); + for (UInt ch=0; ch < pcCU->getPic()->getNumberValidComponents(); ch++) + { + const ComponentID component = ComponentID(ch); + const UInt componentShift = pcCU->getPic()->getComponentScaleX(component) + pcCU->getPic()->getComponentScaleY(component); + ::memset( pcCU->getCbf( component ) , 0, uiQPartNum * sizeof(UChar) ); + ::memset( pcCU->getCoeff(component), 0, (uiWidth*uiHeight*sizeof(TCoeff))>>componentShift ); + ::memset( pcCU->getCrossComponentPredictionAlpha(component), 0, ( uiQPartNum * sizeof(Char) ) ); + } + static const UInt useTS[MAX_NUM_COMPONENT]={0,0,0}; + pcCU->setTransformSkipSubParts ( useTS, 0, pcCU->getDepth(0) ); +#ifdef DEBUG_STRING + sDebug.clear(); + for(UInt i=0; iload( m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_CURR_BEST] ); + + uiBits = 0; + xAddSymbolBitsInter( pcCU, 0, 0, uiBits ); + // we've now encoded the pcCU, and so have a valid bit cost + + + Double dExactCost = m_pcRdCost->calcRdCost( uiBits, uiDistortion ); + dCost = dExactCost; + + // Is our new cost better? + if ( dCost < dCostBest ) + { + if ( !pcCU->getQtRootCbf( 0 ) ) + { + pcYuvResiBest->clear(); // Clear the residual image, if we didn't code it. + } + else + { + xSetResidualQTData( pcYuvResiBest, true, tuLevel0 ); // else set the residual image data pcYUVResiBest from the various temp images. + } + + if( qpMin != qpMax && qp != qpMax ) + { + const UInt uiQPartNum = tuLevel0.GetAbsPartIdxNumParts(); + ::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx(), uiQPartNum * sizeof(UChar) ); + for(UInt i=0; igetPic()->getNumberValidComponents(); i++) + { + const ComponentID compID=ComponentID(i); + const UInt csr = pcCU->getPic()->getComponentScaleX(compID) + pcCU->getPic()->getComponentScaleY(compID); + ::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID ), uiQPartNum * sizeof(UChar) ); + ::memcpy( m_pcQTTempCoeff[compID], pcCU->getCoeff(compID), uiWidth * uiHeight * sizeof( TCoeff ) >> csr ); +#if ADAPTIVE_QP_SELECTION + ::memcpy( m_pcQTTempArlCoeff[compID], pcCU->getArlCoeff(compID), uiWidth * uiHeight * sizeof( TCoeff )>> csr ); +#endif + ::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip(compID), uiQPartNum * sizeof( UChar ) ); + ::memcpy( m_phQTTempCrossComponentPredictionAlpha[compID], pcCU->getCrossComponentPredictionAlpha(compID), uiQPartNum * sizeof(Char) ); + } + } + uiBitsBest = uiBits; + uiDistortionBest = uiDistortion; + dCostBest = dCost; + qpBest = qp; + + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_TEMP_BEST ] ); + } + } + + assert ( dCostBest != MAX_DOUBLE ); + + if( qpMin != qpMax && qpBest != qpMax ) + { + assert( 0 ); // check + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_TEMP_BEST ] ); + + // copy best cbf and trIdx to pcCU + const UInt uiQPartNum = tuLevel0.GetAbsPartIdxNumParts(); + ::memcpy( pcCU->getTransformIdx(), m_puhQTTempTrIdx, uiQPartNum * sizeof(UChar) ); + for(UInt i=0; igetPic()->getNumberValidComponents(); i++) + { + const ComponentID compID=ComponentID(i); + const UInt csr = pcCU->getPic()->getComponentScaleX(compID) + pcCU->getPic()->getComponentScaleY(compID); + ::memcpy( pcCU->getCbf( compID ), m_puhQTTempCbf[compID], uiQPartNum * sizeof(UChar) ); + ::memcpy( pcCU->getCoeff(compID), m_pcQTTempCoeff[compID], uiWidth * uiHeight * sizeof( TCoeff ) >> csr ); +#if ADAPTIVE_QP_SELECTION + ::memcpy( pcCU->getArlCoeff(compID), m_pcQTTempArlCoeff[compID], uiWidth * uiHeight * sizeof( TCoeff ) >> csr ); +#endif + ::memcpy( pcCU->getTransformSkip(compID), m_puhQTTempTransformSkipFlag[compID], uiQPartNum * sizeof( UChar ) ); + ::memcpy( pcCU->getCrossComponentPredictionAlpha(compID), m_phQTTempCrossComponentPredictionAlpha[compID], uiQPartNum * sizeof( Char ) ); + } + } + pcYuvRec->addClip ( pcYuvPred, pcYuvResiBest, 0, uiWidth ); + + // update with clipped distortion and cost (qp estimation loop uses unclipped values) + + uiDistortionBest = 0; + for(UInt ch=0; chgetNumberValidComponents(); ch++) + { + const ComponentID compID=ComponentID(ch); + uiDistortionBest += m_pcRdCost->getDistPart( g_bitDepth[toChannelType(compID)], pcYuvRec->getAddr(compID ), pcYuvRec->getStride(compID ), pcYuvOrg->getAddr(compID ), pcYuvOrg->getStride(compID), uiWidth >> pcYuvOrg->getComponentScaleX(compID), uiHeight >> pcYuvOrg->getComponentScaleY(compID), compID); + } + dCostBest = m_pcRdCost->calcRdCost( uiBitsBest, uiDistortionBest ); + + pcCU->getTotalBits() = uiBitsBest; + pcCU->getTotalDistortion() = uiDistortionBest; + pcCU->getTotalCost() = dCostBest; + + if ( pcCU->isSkipped(0) ) + { + static const UInt cbfZero[MAX_NUM_COMPONENT]={0,0,0}; + pcCU->setCbfSubParts( cbfZero, 0, pcCU->getDepth( 0 ) ); + } + + pcCU->setQPSubParts( qpBest, 0, pcCU->getDepth(0) ); +} + + + +Void TEncSearch::xEstimateResidualQT( TComYuv *pcResi, + Double &rdCost, + UInt &ruiBits, + Distortion &ruiDist, + Distortion *puiZeroDist, + TComTU &rTu + DEBUG_STRING_FN_DECLARE(sDebug) ) +{ + TComDataCU *pcCU = rTu.getCU(); + const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU(); + const UInt uiDepth = rTu.GetTransformDepthTotal(); + const UInt uiTrMode = rTu.GetTransformDepthRel(); + const UInt subTUDepth = uiTrMode + 1; + const UInt numValidComp = pcCU->getPic()->getNumberValidComponents(); + DEBUG_STRING_NEW(sSingleStringComp[MAX_NUM_COMPONENT]) + + assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) ); + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + + UInt SplitFlag = ((pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) && pcCU->isInter(uiAbsPartIdx) && ( pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N )); +#ifdef DEBUG_STRING + const Int debugPredModeMask = DebugStringGetPredModeMask(pcCU->getPredictionMode(uiAbsPartIdx)); +#endif + + Bool bCheckFull; + + if ( SplitFlag && uiDepth == pcCU->getDepth(uiAbsPartIdx) && ( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) ) + { + bCheckFull = false; + } + else + { + bCheckFull = ( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() ); + } + + const Bool bCheckSplit = ( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ); + + assert( bCheckFull || bCheckSplit ); + + // code full block + Double dSingleCost = MAX_DOUBLE; + UInt uiSingleBits = 0; + Distortion uiSingleDistComp [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {{0,0},{0,0},{0,0}}; + Distortion uiSingleDist = 0; + TCoeff uiAbsSum [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {{0,0},{0,0},{0,0}}; + UInt uiBestTransformMode [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {{0,0},{0,0},{0,0}}; + // Stores the best explicit RDPCM mode for a TU encoded without split + UInt bestExplicitRdpcmModeUnSplit[MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {{3,3}, {3,3}, {3,3}}; + Char bestCrossCPredictionAlpha [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {{0,0},{0,0},{0,0}}; + + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + + if( bCheckFull ) + { + Double minCost[MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/]; + Bool checkTransformSkip[MAX_NUM_COMPONENT]; + pcCU->setTrIdxSubParts( uiTrMode, uiAbsPartIdx, uiDepth ); + + m_pcEntropyCoder->resetBits(); + + memset( m_pTempPel, 0, sizeof( Pel ) * rTu.getRect(COMPONENT_Y).width * rTu.getRect(COMPONENT_Y).height ); // not necessary needed for inside of recursion (only at the beginning) + + const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + TCoeff *pcCoeffCurr[MAX_NUM_COMPONENT]; +#if ADAPTIVE_QP_SELECTION + TCoeff *pcArlCoeffCurr[MAX_NUM_COMPONENT]; +#endif + + for(UInt i=0; igetSlice()->getPPS()->getUseTransformSkip() && + TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(compID), pcCU->getSlice()->getPPS()->getTransformSkipLog2MaxSize()) && + (!pcCU->isLosslessCoded(0)); + + const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height; + + TComTURecurse TUIterator(rTu, false, (splitIntoSubTUs ? TComTU::VERTICAL_SPLIT : TComTU::DONT_SPLIT), true, compID); + + const UInt partIdxesPerSubTU = TUIterator.GetAbsPartIdxNumParts(compID); + + do + { + const UInt subTUIndex = TUIterator.GetSectionNumber(); + const UInt subTUAbsPartIdx = TUIterator.GetAbsPartIdxTU(compID); + const TComRectangle &tuCompRect = TUIterator.getRect(compID); + const UInt subTUBufferOffset = tuCompRect.width * tuCompRect.height * subTUIndex; + + TCoeff *currentCoefficients = pcCoeffCurr[compID] + subTUBufferOffset; +#if ADAPTIVE_QP_SELECTION + TCoeff *currentARLCoefficients = pcArlCoeffCurr[compID] + subTUBufferOffset; +#endif + const Bool isCrossCPredictionAvailable = isChroma(compID) + && pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction() + && (pcCU->getCbf(subTUAbsPartIdx, COMPONENT_Y, uiTrMode) != 0); + + Char preCalcAlpha = 0; + const Pel *pLumaResi = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( COMPONENT_Y, rTu.getRect( COMPONENT_Y ).x0, rTu.getRect( COMPONENT_Y ).y0 ); + + if (isCrossCPredictionAvailable) + { + const Bool bUseReconstructedResidualForEstimate = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); + const Pel *const lumaResidualForEstimate = bUseReconstructedResidualForEstimate ? pLumaResi : pcResi->getAddrPix(COMPONENT_Y, tuCompRect.x0, tuCompRect.y0); + const UInt lumaResidualStrideForEstimate = bUseReconstructedResidualForEstimate ? m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y) : pcResi->getStride(COMPONENT_Y); + + preCalcAlpha = xCalcCrossComponentPredictionAlpha(TUIterator, + compID, + lumaResidualForEstimate, + pcResi->getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + tuCompRect.width, + tuCompRect.height, + lumaResidualStrideForEstimate, + pcResi->getStride(compID)); + } + + const Int transformSkipModesToTest = checkTransformSkip[compID] ? 2 : 1; + const Int crossCPredictionModesToTest = (preCalcAlpha != 0) ? 2 : 1; // preCalcAlpha cannot be anything other than 0 if isCrossCPredictionAvailable is false + + const Bool isOneMode = (crossCPredictionModesToTest == 1) && (transformSkipModesToTest == 1); + + for (Int transformSkipModeId = 0; transformSkipModeId < transformSkipModesToTest; transformSkipModeId++) + { + pcCU->setTransformSkipPartRange(transformSkipModeId, compID, subTUAbsPartIdx, partIdxesPerSubTU); + + for (Int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++) + { + const Bool isFirstMode = (transformSkipModeId == 0) && (crossCPredictionModeId == 0); + const Bool bUseCrossCPrediction = crossCPredictionModeId != 0; + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + m_pcEntropyCoder->resetBits(); + + pcCU->setTransformSkipPartRange(transformSkipModeId, compID, subTUAbsPartIdx, partIdxesPerSubTU); + pcCU->setCrossComponentPredictionAlphaPartRange((bUseCrossCPrediction ? preCalcAlpha : 0), compID, subTUAbsPartIdx, partIdxesPerSubTU ); + + if ((compID != COMPONENT_Cr) && ((transformSkipModeId == 1) ? m_pcEncCfg->getUseRDOQTS() : m_pcEncCfg->getUseRDOQ())) + { + m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, tuCompRect.width, tuCompRect.height, toChannelType(compID)); + } + +#if RDOQ_CHROMA_LAMBDA + m_pcTrQuant->selectLambda(compID); +#endif + + Pel *pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0); + UInt resiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID); + + TCoeff bestCoeffComp [MAX_TU_SIZE*MAX_TU_SIZE]; + Pel bestResiComp [MAX_TU_SIZE*MAX_TU_SIZE]; + +#if ADAPTIVE_QP_SELECTION + TCoeff bestArlCoeffComp[MAX_TU_SIZE*MAX_TU_SIZE]; +#endif + TCoeff currAbsSum = 0; + UInt currCompBits = 0; + Distortion currCompDist = 0; + Double currCompCost = 0; + UInt nonCoeffBits = 0; + Distortion nonCoeffDist = 0; + Double nonCoeffCost = 0; + + if(!isOneMode && !isFirstMode) + { + memcpy(bestCoeffComp, currentCoefficients, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height)); +#if ADAPTIVE_QP_SELECTION + memcpy(bestArlCoeffComp, currentARLCoefficients, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height)); +#endif + for(Int y = 0; y < tuCompRect.height; y++) + { + memcpy(&bestResiComp[y * tuCompRect.width], (pcResiCurrComp + (y * resiStride)), (sizeof(Pel) * tuCompRect.width)); + } + } + + if (bUseCrossCPrediction) + { + TComTrQuant::crossComponentPrediction(TUIterator, + compID, + pLumaResi, + pcResi->getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + crossCPredictedResidualBuffer, + tuCompRect.width, + tuCompRect.height, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y), + pcResi->getStride(compID), + tuCompRect.width, + false); + + m_pcTrQuant->transformNxN(TUIterator, compID, crossCPredictedResidualBuffer, tuCompRect.width, currentCoefficients, +#if ADAPTIVE_QP_SELECTION + currentARLCoefficients, +#endif + currAbsSum, cQP); + } + else + { + m_pcTrQuant->transformNxN(TUIterator, compID, pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), pcResi->getStride(compID), currentCoefficients, +#if ADAPTIVE_QP_SELECTION + currentARLCoefficients, +#endif + currAbsSum, cQP); + } + + if(isFirstMode || (currAbsSum == 0)) + { + if (bUseCrossCPrediction) + { + TComTrQuant::crossComponentPrediction(TUIterator, + compID, + pLumaResi, + m_pTempPel, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + tuCompRect.width, + tuCompRect.height, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y), + tuCompRect.width, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID), + true); + + nonCoeffDist = m_pcRdCost->getDistPart( g_bitDepth[toChannelType(compID)], m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride( compID ), pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), + pcResi->getStride(compID), tuCompRect.width, tuCompRect.height, compID); // initialized with zero residual destortion + } + else + { + nonCoeffDist = m_pcRdCost->getDistPart( g_bitDepth[toChannelType(compID)], m_pTempPel, tuCompRect.width, pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), + pcResi->getStride(compID), tuCompRect.width, tuCompRect.height, compID); // initialized with zero residual destortion + } + + m_pcEntropyCoder->encodeQtCbfZero( TUIterator, toChannelType(compID) ); + + if ( isCrossCPredictionAvailable ) + { + m_pcEntropyCoder->encodeCrossComponentPrediction( TUIterator, compID ); + } + + nonCoeffBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + nonCoeffCost = m_pcRdCost->calcRdCost( nonCoeffBits, nonCoeffDist ); + } + + if((puiZeroDist != NULL) && isFirstMode) + { + *puiZeroDist += nonCoeffDist; // initialized with zero residual destortion + } + + DEBUG_STRING_NEW(sSingleStringTest) + + if( currAbsSum > 0 ) //if non-zero coefficients are present, a residual needs to be derived for further prediction + { + if (isFirstMode) + { + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + m_pcEntropyCoder->resetBits(); + } + + m_pcEntropyCoder->encodeQtCbf( TUIterator, compID, true ); + + if (isCrossCPredictionAvailable) + { + m_pcEntropyCoder->encodeCrossComponentPrediction( TUIterator, compID ); + } + + m_pcEntropyCoder->encodeCoeffNxN( TUIterator, currentCoefficients, compID ); + currCompBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + + pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ); + + m_pcTrQuant->invTransformNxN( TUIterator, compID, pcResiCurrComp, m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID), currentCoefficients, cQP DEBUG_STRING_PASS_INTO_OPTIONAL(&sSingleStringTest, (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask)) ); + + if (bUseCrossCPrediction) + { + TComTrQuant::crossComponentPrediction(TUIterator, + compID, + pLumaResi, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + tuCompRect.width, + tuCompRect.height, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y), + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID ), + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID ), + true); + } + + currCompDist = m_pcRdCost->getDistPart( g_bitDepth[toChannelType(compID)], m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID), + pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), + pcResi->getStride(compID), + tuCompRect.width, tuCompRect.height, compID); + + currCompCost = m_pcRdCost->calcRdCost(currCompBits, currCompDist); + + if (pcCU->isLosslessCoded(0)) nonCoeffCost = MAX_DOUBLE; + } + else if ((transformSkipModeId == 1) && !bUseCrossCPrediction) + { + currCompCost = MAX_DOUBLE; + } + else + { + currCompBits = nonCoeffBits; + currCompDist = nonCoeffDist; + currCompCost = nonCoeffCost; + } + + // evaluate + if ((currCompCost < minCost[compID][subTUIndex]) || ((transformSkipModeId == 1) && (currCompCost == minCost[compID][subTUIndex]))) + { + bestExplicitRdpcmModeUnSplit[compID][subTUIndex] = pcCU->getExplicitRdpcmMode(compID, subTUAbsPartIdx); + + if(isFirstMode) //check for forced null + { + if((nonCoeffCost < currCompCost) || (currAbsSum == 0)) + { + memset(currentCoefficients, 0, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height)); + + currAbsSum = 0; + currCompBits = nonCoeffBits; + currCompDist = nonCoeffDist; + currCompCost = nonCoeffCost; + } + } + +#ifdef DEBUG_STRING + if (currAbsSum > 0) + { + DEBUG_STRING_SWAP(sSingleStringComp[compID], sSingleStringTest) + } + else + { + sSingleStringComp[compID].clear(); + } +#endif + + uiAbsSum [compID][subTUIndex] = currAbsSum; + uiSingleDistComp [compID][subTUIndex] = currCompDist; + minCost [compID][subTUIndex] = currCompCost; + uiBestTransformMode [compID][subTUIndex] = transformSkipModeId; + bestCrossCPredictionAlpha[compID][subTUIndex] = (crossCPredictionModeId == 1) ? pcCU->getCrossComponentPredictionAlpha(subTUAbsPartIdx, compID) : 0; + + if (uiAbsSum[compID][subTUIndex] == 0) + { + if (bUseCrossCPrediction) + { + TComTrQuant::crossComponentPrediction(TUIterator, + compID, + pLumaResi, + m_pTempPel, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0), + tuCompRect.width, + tuCompRect.height, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y), + tuCompRect.width, + m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID), + true); + } + else + { + pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0); + const UInt uiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID); + for(UInt uiY = 0; uiY < tuCompRect.height; uiY++) + { + memset(pcResiCurrComp, 0, (sizeof(Pel) * tuCompRect.width)); + pcResiCurrComp += uiStride; + } + } + } + } + else + { + // reset + memcpy(currentCoefficients, bestCoeffComp, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height)); +#if ADAPTIVE_QP_SELECTION + memcpy(currentARLCoefficients, bestArlCoeffComp, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height)); +#endif + for (Int y = 0; y < tuCompRect.height; y++) + { + memcpy((pcResiCurrComp + (y * resiStride)), &bestResiComp[y * tuCompRect.width], (sizeof(Pel) * tuCompRect.width)); + } + } + } + } + + pcCU->setExplicitRdpcmModePartRange ( bestExplicitRdpcmModeUnSplit[compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU); + pcCU->setTransformSkipPartRange ( uiBestTransformMode [compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU ); + pcCU->setCbfPartRange ((((uiAbsSum [compID][subTUIndex] > 0) ? 1 : 0) << uiTrMode), compID, subTUAbsPartIdx, partIdxesPerSubTU ); + pcCU->setCrossComponentPredictionAlphaPartRange( bestCrossCPredictionAlpha [compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU ); + } //end of sub-TU loop + while (TUIterator.nextSection(rTu)); + } // processing section + } // component loop + + for(UInt ch = 0; ch < numValidComp; ch++) + { + const ComponentID compID = ComponentID(ch); + if (rTu.ProcessComponentSection(compID) && (rTu.getRect(compID).width != rTu.getRect(compID).height)) + { + offsetSubTUCBFs(rTu, compID); //the CBFs up to now have been defined for two sub-TUs - shift them down a level and replace with the parent level CBF + } + } + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + m_pcEntropyCoder->resetBits(); + + if( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) + { + m_pcEntropyCoder->encodeTransformSubdivFlag( 0, 5 - uiLog2TrSize ); + } + + for(UInt ch = 0; ch < numValidComp; ch++) + { + const UInt chOrderChange = ((ch + 1) == numValidComp) ? 0 : (ch + 1); + const ComponentID compID=ComponentID(chOrderChange); + if( rTu.ProcessComponentSection(compID) ) + { + m_pcEntropyCoder->encodeQtCbf( rTu, compID, true ); + } + } + + for(UInt ch = 0; ch < numValidComp; ch++) + { + const ComponentID compID=ComponentID(ch); + if (rTu.ProcessComponentSection(compID)) + { + if(isChroma(compID) && (uiAbsSum[COMPONENT_Y][0] != 0)) + { + m_pcEntropyCoder->encodeCrossComponentPrediction( rTu, compID ); + } + + m_pcEntropyCoder->encodeCoeffNxN( rTu, pcCoeffCurr[compID], compID ); + for (UInt subTUIndex = 0; subTUIndex < 2; subTUIndex++) uiSingleDist += uiSingleDistComp[compID][subTUIndex]; + } + } + + uiSingleBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + + dSingleCost = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDist ); + } // check full + + // code sub-blocks + if( bCheckSplit ) + { + if( bCheckFull ) + { + m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] ); + m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + } + Distortion uiSubdivDist = 0; + UInt uiSubdivBits = 0; + Double dSubdivCost = 0.0; + + //save the non-split CBFs in case we need to restore them later + + UInt bestCBF [MAX_NUM_COMPONENT]; + UInt bestsubTUCBF[MAX_NUM_COMPONENT][2]; + for(UInt ch = 0; ch < numValidComp; ch++) + { + const ComponentID compID=ComponentID(ch); + + if (rTu.ProcessComponentSection(compID)) + { + bestCBF[compID] = pcCU->getCbf(uiAbsPartIdx, compID, uiTrMode); + + const TComRectangle &tuCompRect = rTu.getRect(compID); + if (tuCompRect.width != tuCompRect.height) + { + const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> 1; + + for (UInt subTU = 0; subTU < 2; subTU++) + bestsubTUCBF[compID][subTU] = pcCU->getCbf ((uiAbsPartIdx + (subTU * partIdxesPerSubTU)), compID, subTUDepth); + } + } + } + + + TComTURecurse tuRecurseChild(rTu, false); + const UInt uiQPartNumSubdiv = tuRecurseChild.GetAbsPartIdxNumParts(); + + DEBUG_STRING_NEW(sSplitString[MAX_NUM_COMPONENT]) + + do + { + DEBUG_STRING_NEW(childString) + xEstimateResidualQT( pcResi, dSubdivCost, uiSubdivBits, uiSubdivDist, bCheckFull ? NULL : puiZeroDist, tuRecurseChild DEBUG_STRING_PASS_INTO(childString)); +#ifdef DEBUG_STRING + // split the string by component and append to the relevant output (because decoder decodes in channel order, whereas this search searches by TU-order) + std::size_t lastPos=0; + const std::size_t endStrng=childString.find(debug_reorder_data_inter_token[MAX_NUM_COMPONENT], lastPos); + for(UInt ch = 0; ch < numValidComp; ch++) + { + if (lastPos!=std::string::npos && childString.find(debug_reorder_data_inter_token[ch], lastPos)==lastPos) lastPos+=strlen(debug_reorder_data_inter_token[ch]); // skip leading string + std::size_t pos=childString.find(debug_reorder_data_inter_token[ch+1], lastPos); + if (pos!=std::string::npos && pos>endStrng) lastPos=endStrng; + sSplitString[ch]+=childString.substr(lastPos, (pos==std::string::npos)? std::string::npos : (pos-lastPos) ); + lastPos=pos; + } +#endif + } + while ( tuRecurseChild.nextSection(rTu) ) ; + + UInt uiCbfAny=0; + for(UInt ch = 0; ch < numValidComp; ch++) + { + UInt uiYUVCbf = 0; + for( UInt ui = 0; ui < 4; ++ui ) + { + uiYUVCbf |= pcCU->getCbf( uiAbsPartIdx + ui * uiQPartNumSubdiv, ComponentID(ch), uiTrMode + 1 ); + } + UChar *pBase=pcCU->getCbf( ComponentID(ch) ); + const UInt flags=uiYUVCbf << uiTrMode; + for( UInt ui = 0; ui < 4 * uiQPartNumSubdiv; ++ui ) + { + pBase[uiAbsPartIdx + ui] |= flags; + } + uiCbfAny|=uiYUVCbf; + } + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] ); + m_pcEntropyCoder->resetBits(); + + // when compID isn't a channel, code Cbfs: + xEncodeResidualQT( MAX_NUM_COMPONENT, rTu ); + for(UInt ch = 0; ch < numValidComp; ch++) + { + xEncodeResidualQT( ComponentID(ch), rTu ); + } + + uiSubdivBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + dSubdivCost = m_pcRdCost->calcRdCost( uiSubdivBits, uiSubdivDist ); + + if (!bCheckFull || (uiCbfAny && (dSubdivCost < dSingleCost))) + { + rdCost += dSubdivCost; + ruiBits += uiSubdivBits; + ruiDist += uiSubdivDist; +#ifdef DEBUG_STRING + for(UInt ch = 0; ch < numValidComp; ch++) + { + DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[ch]) + DEBUG_STRING_APPEND(sDebug, sSplitString[ch]) + } +#endif + } + else + { + rdCost += dSingleCost; + ruiBits += uiSingleBits; + ruiDist += uiSingleDist; + + //restore state to unsplit + + pcCU->setTrIdxSubParts( uiTrMode, uiAbsPartIdx, uiDepth ); + + for(UInt ch = 0; ch < numValidComp; ch++) + { + const ComponentID compID=ComponentID(ch); + + DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[ch]) + if (rTu.ProcessComponentSection(compID)) + { + DEBUG_STRING_APPEND(sDebug, sSingleStringComp[compID]) + + const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height; + const UInt numberOfSections = splitIntoSubTUs ? 2 : 1; + const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> (splitIntoSubTUs ? 1 : 0); + + for (UInt subTUIndex = 0; subTUIndex < numberOfSections; subTUIndex++) + { + const UInt uisubTUPartIdx = uiAbsPartIdx + (subTUIndex * partIdxesPerSubTU); + + if (splitIntoSubTUs) + { + const UChar combinedCBF = (bestsubTUCBF[compID][subTUIndex] << subTUDepth) | (bestCBF[compID] << uiTrMode); + pcCU->setCbfPartRange(combinedCBF, compID, uisubTUPartIdx, partIdxesPerSubTU); + } + else + { + pcCU->setCbfPartRange((bestCBF[compID] << uiTrMode), compID, uisubTUPartIdx, partIdxesPerSubTU); + } + + pcCU->setCrossComponentPredictionAlphaPartRange(bestCrossCPredictionAlpha[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU); + pcCU->setTransformSkipPartRange(uiBestTransformMode[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU); + pcCU->setExplicitRdpcmModePartRange(bestExplicitRdpcmModeUnSplit[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU); + } + } + } + + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] ); + } + } + else + { + rdCost += dSingleCost; + ruiBits += uiSingleBits; + ruiDist += uiSingleDist; +#ifdef DEBUG_STRING + for(UInt ch = 0; ch < numValidComp; ch++) + { + const ComponentID compID=ComponentID(ch); + DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[compID]) + + if (rTu.ProcessComponentSection(compID)) + { + DEBUG_STRING_APPEND(sDebug, sSingleStringComp[compID]) + } + } +#endif + } + DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[MAX_NUM_COMPONENT]) +} + + + +Void TEncSearch::xEncodeResidualQT( const ComponentID compID, TComTU &rTu ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + const UInt uiCurrTrMode = rTu.GetTransformDepthRel(); + assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) ); + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + + const Bool bSubdiv = uiCurrTrMode != uiTrMode; + + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + + if (compID==MAX_NUM_COMPONENT) // we are not processing a channel, instead we always recurse and code the CBFs + { + if( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() && uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) + { + m_pcEntropyCoder->encodeTransformSubdivFlag( bSubdiv, 5 - uiLog2TrSize ); + } + + assert( !pcCU->isIntra(uiAbsPartIdx) ); + + const Bool bFirstCbfOfCU = uiCurrTrMode == 0; + + for (UInt ch=COMPONENT_Cb; chgetPic()->getNumberValidComponents(); ch++) + { + const ComponentID compIdInner=ComponentID(ch); + if( bFirstCbfOfCU || rTu.ProcessingAllQuadrants(compIdInner) ) + { + if( bFirstCbfOfCU || pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode - 1 ) ) + { + m_pcEntropyCoder->encodeQtCbf( rTu, compIdInner, !bSubdiv ); + } + } + else + { + assert( pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode ) == pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode - 1 ) ); + } + } + + if (!bSubdiv) + { + m_pcEntropyCoder->encodeQtCbf( rTu, COMPONENT_Y, true ); + } + } + + if( !bSubdiv ) + { + if (compID != MAX_NUM_COMPONENT) // we have already coded the CBFs, so now we code coefficients + { + if (rTu.ProcessComponentSection(compID)) + { + if (isChroma(compID) && (pcCU->getCbf(uiAbsPartIdx, COMPONENT_Y, uiTrMode) != 0)) + { + m_pcEntropyCoder->encodeCrossComponentPrediction(rTu, compID); + } + + if (pcCU->getCbf(uiAbsPartIdx, compID, uiTrMode) != 0) + { + const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + TCoeff *pcCoeffCurr = m_ppcQTTempCoeff[compID][uiQTTempAccessLayer] + rTu.getCoefficientOffset(compID); + m_pcEntropyCoder->encodeCoeffNxN( rTu, pcCoeffCurr, compID ); + } + } + } + } + else + { + if( compID==MAX_NUM_COMPONENT || pcCU->getCbf( uiAbsPartIdx, compID, uiCurrTrMode ) ) + { + TComTURecurse tuRecurseChild(rTu, false); + do + { + xEncodeResidualQT( compID, tuRecurseChild ); + } while (tuRecurseChild.nextSection(rTu)); + } + } +} + + + + +Void TEncSearch::xSetResidualQTData( TComYuv* pcResi, Bool bSpatial, TComTU &rTu ) +{ + TComDataCU* pcCU=rTu.getCU(); + const UInt uiCurrTrMode=rTu.GetTransformDepthRel(); + const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); + assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) ); + const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx ); + TComSPS *sps=pcCU->getSlice()->getSPS(); + + if( uiCurrTrMode == uiTrMode ) + { + const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize(); + const UInt uiQTTempAccessLayer = sps->getQuadtreeTULog2MaxSize() - uiLog2TrSize; + + if( bSpatial ) + { + // Data to be copied is in the spatial domain, i.e., inverse-transformed. + + for(UInt i=0; igetNumberValidComponents(); i++) + { + const ComponentID compID=ComponentID(i); + if (rTu.ProcessComponentSection(compID)) + { + const TComRectangle &rectCompTU(rTu.getRect(compID)); + m_pcQTTempTComYuv[uiQTTempAccessLayer].copyPartToPartComponentMxN ( compID, pcResi, rectCompTU ); + } + } + } + else + { + for (UInt ch=0; ch < getNumberValidComponents(sps->getChromaFormatIdc()); ch++) + { + const ComponentID compID = ComponentID(ch); + if (rTu.ProcessComponentSection(compID)) + { + const TComRectangle &rectCompTU(rTu.getRect(compID)); + const UInt numCoeffInBlock = rectCompTU.width * rectCompTU.height; + const UInt offset = rTu.getCoefficientOffset(compID); + TCoeff* dest = pcCU->getCoeff(compID) + offset; + const TCoeff* src = m_ppcQTTempCoeff[compID][uiQTTempAccessLayer] + offset; + ::memcpy( dest, src, sizeof(TCoeff)*numCoeffInBlock ); + +#if ADAPTIVE_QP_SELECTION + TCoeff* pcArlCoeffSrc = m_ppcQTTempArlCoeff[compID][uiQTTempAccessLayer] + offset; + TCoeff* pcArlCoeffDst = pcCU->getArlCoeff(compID) + offset; + ::memcpy( pcArlCoeffDst, pcArlCoeffSrc, sizeof( TCoeff ) * numCoeffInBlock ); +#endif + } + } + } + } + else + { + + TComTURecurse tuRecurseChild(rTu, false); + do + { + xSetResidualQTData( pcResi, bSpatial, tuRecurseChild ); + } while (tuRecurseChild.nextSection(rTu)); + } +} + + + + +UInt TEncSearch::xModeBitsIntra( TComDataCU* pcCU, UInt uiMode, UInt uiPartOffset, UInt uiDepth, UInt uiInitTrDepth, const ChannelType chType ) +{ + // Reload only contexts required for coding intra mode information + m_pcRDGoOnSbacCoder->loadIntraDirMode( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST], chType ); + + // Temporarily set the intra dir being tested, and only + // for absPartIdx, since encodeIntraDirModeLuma/Chroma only use + // the entry at absPartIdx. + + UChar &rIntraDirVal=pcCU->getIntraDir( chType )[uiPartOffset]; + UChar origVal=rIntraDirVal; + rIntraDirVal = uiMode; + //pcCU->setIntraDirSubParts ( chType, uiMode, uiPartOffset, uiDepth + uiInitTrDepth ); + + m_pcEntropyCoder->resetBits(); + if (isLuma(chType)) + m_pcEntropyCoder->encodeIntraDirModeLuma ( pcCU, uiPartOffset); + else + m_pcEntropyCoder->encodeIntraDirModeChroma ( pcCU, uiPartOffset); + + rIntraDirVal = origVal; // restore + + return m_pcEntropyCoder->getNumberOfWrittenBits(); +} + + + + +UInt TEncSearch::xUpdateCandList( UInt uiMode, Double uiCost, UInt uiFastCandNum, UInt * CandModeList, Double * CandCostList ) +{ + UInt i; + UInt shift=0; + + while ( shiftgetMergeFlag( 0 ) && pcCU->getPartitionSize( 0 ) == SIZE_2Nx2N && !pcCU->getQtRootCbf( 0 )) + { + pcCU->setSkipFlagSubParts( true, 0, pcCU->getDepth(0) ); + + m_pcEntropyCoder->resetBits(); + if(pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag(pcCU, 0, true); + } + m_pcEntropyCoder->encodeSkipFlag(pcCU, 0, true); + m_pcEntropyCoder->encodeMergeIndex(pcCU, 0, true); + + ruiBits += m_pcEntropyCoder->getNumberOfWrittenBits(); + } + else + { + m_pcEntropyCoder->resetBits(); + + if(pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) + { + m_pcEntropyCoder->encodeCUTransquantBypassFlag(pcCU, 0, true); + } + + m_pcEntropyCoder->encodeSkipFlag ( pcCU, 0, true ); + m_pcEntropyCoder->encodePredMode( pcCU, 0, true ); + m_pcEntropyCoder->encodePartSize( pcCU, 0, pcCU->getDepth(0), true ); + m_pcEntropyCoder->encodePredInfo( pcCU, 0 ); + + Bool codeDeltaQp = false; + Bool codeChromaQpAdj = false; + m_pcEntropyCoder->encodeCoeff ( pcCU, 0, pcCU->getDepth(0), codeDeltaQp, codeChromaQpAdj ); + + ruiBits += m_pcEntropyCoder->getNumberOfWrittenBits(); + } +} + + + + + +/** + * \brief Generate half-sample interpolated block + * + * \param pattern Reference picture ROI + * \param biPred Flag indicating whether block is for biprediction + */ +Void TEncSearch::xExtDIFUpSamplingH( TComPattern* pattern, Bool biPred ) +{ + Int width = pattern->getROIYWidth(); + Int height = pattern->getROIYHeight(); + Int srcStride = pattern->getPatternLStride(); + + Int intStride = m_filteredBlockTmp[0].getStride(COMPONENT_Y); + Int dstStride = m_filteredBlock[0][0].getStride(COMPONENT_Y); + Pel *intPtr; + Pel *dstPtr; + Int filterSize = NTAPS_LUMA; + Int halfFilterSize = (filterSize>>1); + Pel *srcPtr = pattern->getROIY() - halfFilterSize*srcStride - 1; + + const ChromaFormat chFmt = m_filteredBlock[0][0].getChromaFormat(); + + m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[0].getAddr(COMPONENT_Y), intStride, width+1, height+filterSize, 0, false, chFmt); + m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[2].getAddr(COMPONENT_Y), intStride, width+1, height+filterSize, 2, false, chFmt); + + intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + halfFilterSize * intStride + 1; + dstPtr = m_filteredBlock[0][0].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+0, height+0, 0, false, true, chFmt); + + intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1; + dstPtr = m_filteredBlock[2][0].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+0, height+1, 2, false, true, chFmt); + + intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + halfFilterSize * intStride; + dstPtr = m_filteredBlock[0][2].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+1, height+0, 0, false, true, chFmt); + + intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[2][2].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+1, height+1, 2, false, true, chFmt); +} + + + + + +/** + * \brief Generate quarter-sample interpolated blocks + * + * \param pattern Reference picture ROI + * \param halfPelRef Half-pel mv + * \param biPred Flag indicating whether block is for biprediction + */ +Void TEncSearch::xExtDIFUpSamplingQ( TComPattern* pattern, TComMv halfPelRef, Bool biPred ) +{ + Int width = pattern->getROIYWidth(); + Int height = pattern->getROIYHeight(); + Int srcStride = pattern->getPatternLStride(); + + Pel *srcPtr; + Int intStride = m_filteredBlockTmp[0].getStride(COMPONENT_Y); + Int dstStride = m_filteredBlock[0][0].getStride(COMPONENT_Y); + Pel *intPtr; + Pel *dstPtr; + Int filterSize = NTAPS_LUMA; + + Int halfFilterSize = (filterSize>>1); + + Int extHeight = (halfPelRef.getVer() == 0) ? height + filterSize : height + filterSize-1; + + const ChromaFormat chFmt = m_filteredBlock[0][0].getChromaFormat(); + + // Horizontal filter 1/4 + srcPtr = pattern->getROIY() - halfFilterSize * srcStride - 1; + intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() > 0) + { + srcPtr += srcStride; + } + if (halfPelRef.getHor() >= 0) + { + srcPtr += 1; + } + m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, intPtr, intStride, width, extHeight, 1, false, chFmt); + + // Horizontal filter 3/4 + srcPtr = pattern->getROIY() - halfFilterSize*srcStride - 1; + intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() > 0) + { + srcPtr += srcStride; + } + if (halfPelRef.getHor() > 0) + { + srcPtr += 1; + } + m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, intPtr, intStride, width, extHeight, 3, false, chFmt); + + // Generate @ 1,1 + intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[1][1].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() == 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt); + + // Generate @ 3,1 + intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[3][1].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt); + + if (halfPelRef.getVer() != 0) + { + // Generate @ 2,1 + intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[2][1].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() == 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 2, false, true, chFmt); + + // Generate @ 2,3 + intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[2][3].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() == 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 2, false, true, chFmt); + } + else + { + // Generate @ 0,1 + intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + halfFilterSize * intStride; + dstPtr = m_filteredBlock[0][1].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 0, false, true, chFmt); + + // Generate @ 0,3 + intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + halfFilterSize * intStride; + dstPtr = m_filteredBlock[0][3].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 0, false, true, chFmt); + } + + if (halfPelRef.getHor() != 0) + { + // Generate @ 1,2 + intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[1][2].getAddr(COMPONENT_Y); + if (halfPelRef.getHor() > 0) + { + intPtr += 1; + } + if (halfPelRef.getVer() >= 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt); + + // Generate @ 3,2 + intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[3][2].getAddr(COMPONENT_Y); + if (halfPelRef.getHor() > 0) + { + intPtr += 1; + } + if (halfPelRef.getVer() > 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt); + } + else + { + // Generate @ 1,0 + intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1; + dstPtr = m_filteredBlock[1][0].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() >= 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt); + + // Generate @ 3,0 + intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1; + dstPtr = m_filteredBlock[3][0].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() > 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt); + } + + // Generate @ 1,3 + intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[1][3].getAddr(COMPONENT_Y); + if (halfPelRef.getVer() == 0) + { + intPtr += intStride; + } + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt); + + // Generate @ 3,3 + intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride; + dstPtr = m_filteredBlock[3][3].getAddr(COMPONENT_Y); + m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt); +} + + + + + +/** set wp tables + * \param TComDataCU* pcCU + * \param iRefIdx + * \param eRefPicListCur + * \returns Void + */ +Void TEncSearch::setWpScalingDistParam( TComDataCU* pcCU, Int iRefIdx, RefPicList eRefPicListCur ) +{ + if ( iRefIdx<0 ) + { + m_cDistParam.bApplyWeight = false; + return; + } + + TComSlice *pcSlice = pcCU->getSlice(); + TComPPS *pps = pcCU->getSlice()->getPPS(); + WPScalingParam *wp0 , *wp1; + + m_cDistParam.bApplyWeight = ( pcSlice->getSliceType()==P_SLICE && pps->getUseWP() ) || ( pcSlice->getSliceType()==B_SLICE && pps->getWPBiPred() ) ; + + if ( !m_cDistParam.bApplyWeight ) return; + + Int iRefIdx0 = ( eRefPicListCur == REF_PIC_LIST_0 ) ? iRefIdx : (-1); + Int iRefIdx1 = ( eRefPicListCur == REF_PIC_LIST_1 ) ? iRefIdx : (-1); + + getWpScaling( pcCU, iRefIdx0, iRefIdx1, wp0 , wp1 ); + + if ( iRefIdx0 < 0 ) wp0 = NULL; + if ( iRefIdx1 < 0 ) wp1 = NULL; + + m_cDistParam.wpCur = NULL; + + if ( eRefPicListCur == REF_PIC_LIST_0 ) + { + m_cDistParam.wpCur = wp0; + } + else + { + m_cDistParam.wpCur = wp1; + } +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncSearch.h b/jctvc/TLibEncoder/TEncSearch.h new file mode 100644 index 0000000..fda6ef9 --- /dev/null +++ b/jctvc/TLibEncoder/TEncSearch.h @@ -0,0 +1,474 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncSearch.h + \brief encoder search class (header) +*/ + +#ifndef __TENCSEARCH__ +#define __TENCSEARCH__ + +// Include files +#include "TLibCommon/TComYuv.h" +#include "TLibCommon/TComMotionInfo.h" +#include "TLibCommon/TComPattern.h" +#include "TLibCommon/TComPrediction.h" +#include "TLibCommon/TComTrQuant.h" +#include "TLibCommon/TComPic.h" +#include "TLibCommon/TComRectangle.h" +#include "TEncEntropy.h" +#include "TEncSbac.h" +#include "TEncCfg.h" + + +//! \ingroup TLibEncoder +//! \{ + +class TEncCu; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +static const UInt MAX_NUM_REF_LIST_ADAPT_SR=2; +static const UInt MAX_IDX_ADAPT_SR=33; +static const UInt NUM_MV_PREDICTORS=3; + +/// encoder search class +class TEncSearch : public TComPrediction +{ +private: + TCoeff** m_ppcQTTempCoeff[MAX_NUM_COMPONENT /* 0->Y, 1->Cb, 2->Cr*/]; + TCoeff* m_pcQTTempCoeff[MAX_NUM_COMPONENT]; +#if ADAPTIVE_QP_SELECTION + TCoeff** m_ppcQTTempArlCoeff[MAX_NUM_COMPONENT]; + TCoeff* m_pcQTTempArlCoeff[MAX_NUM_COMPONENT]; +#endif + UChar* m_puhQTTempTrIdx; + UChar* m_puhQTTempCbf[MAX_NUM_COMPONENT]; + + TComYuv* m_pcQTTempTComYuv; + TComYuv m_tmpYuvPred; // To be used in xGetInterPredictionError() to avoid constant memory allocation/deallocation + + Char* m_phQTTempCrossComponentPredictionAlpha[MAX_NUM_COMPONENT]; + Pel* m_pSharedPredTransformSkip[MAX_NUM_COMPONENT]; + TCoeff* m_pcQTTempTUCoeff[MAX_NUM_COMPONENT]; + UChar* m_puhQTTempTransformSkipFlag[MAX_NUM_COMPONENT]; + TComYuv m_pcQTTempTransformSkipTComYuv; +#if ADAPTIVE_QP_SELECTION + TCoeff* m_ppcQTTempTUArlCoeff[MAX_NUM_COMPONENT]; +#endif + +protected: + // interface to option + TEncCfg* m_pcEncCfg; + + // interface to classes + TComTrQuant* m_pcTrQuant; + TComRdCost* m_pcRdCost; + TEncEntropy* m_pcEntropyCoder; + + // ME parameters + Int m_iSearchRange; + Int m_bipredSearchRange; // Search range for bi-prediction + Int m_iFastSearch; + Int m_aaiAdaptSR[MAX_NUM_REF_LIST_ADAPT_SR][MAX_IDX_ADAPT_SR]; + TComMv m_cSrchRngLT; + TComMv m_cSrchRngRB; + TComMv m_acMvPredictors[NUM_MV_PREDICTORS]; // Left, Above, AboveRight. enum MVP_DIR first NUM_MV_PREDICTORS entries are suitable for accessing. + + // RD computation + TEncSbac*** m_pppcRDSbacCoder; + TEncSbac* m_pcRDGoOnSbacCoder; + DistParam m_cDistParam; + + // Misc. + Pel* m_pTempPel; + const UInt* m_puiDFilter; + Int m_iMaxDeltaQP; + + // AMVP cost computation + // UInt m_auiMVPIdxCost[AMVP_MAX_NUM_CANDS+1][AMVP_MAX_NUM_CANDS]; + UInt m_auiMVPIdxCost[AMVP_MAX_NUM_CANDS+1][AMVP_MAX_NUM_CANDS+1]; //th array bounds + + TComMv m_integerMv2Nx2N[NUM_REF_PIC_LIST_01][MAX_NUM_REF]; + +public: + TEncSearch(); + virtual ~TEncSearch(); + + Void init( TEncCfg* pcEncCfg, + TComTrQuant* pcTrQuant, + Int iSearchRange, + Int bipredSearchRange, + Int iFastSearch, + Int iMaxDeltaQP, + TEncEntropy* pcEntropyCoder, + TComRdCost* pcRdCost, + TEncSbac*** pppcRDSbacCoder, + TEncSbac* pcRDGoOnSbacCoder ); + +protected: + + /// sub-function for motion vector refinement used in fractional-pel accuracy + Distortion xPatternRefinement( TComPattern* pcPatternKey, + TComMv baseRefMv, + Int iFrac, TComMv& rcMvFrac, Bool bAllowUseOfHadamard + ); + + typedef struct + { + Pel* piRefY; + Int iYStride; + Int iBestX; + Int iBestY; + UInt uiBestRound; + UInt uiBestDistance; + Distortion uiBestSad; + UChar ucPointNr; + } IntTZSearchStruct; + + // sub-functions for ME + __inline Void xTZSearchHelp ( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, const Int iSearchX, const Int iSearchY, const UChar ucPointNr, const UInt uiDistance ); + __inline Void xTZ2PointSearch ( TComPattern* pcPatternKey, IntTZSearchStruct& rcStrukt, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB ); + __inline Void xTZ8PointSquareSearch ( TComPattern* pcPatternKey, IntTZSearchStruct& rcStrukt, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, const Int iStartX, const Int iStartY, const Int iDist ); + __inline Void xTZ8PointDiamondSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStrukt, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, const Int iStartX, const Int iStartY, const Int iDist ); + + Void xGetInterPredictionError( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, Distortion& ruiSAD, Bool Hadamard ); + +public: + Void preestChromaPredMode ( TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv ); + + Void estIntraPredQT ( TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + TComYuv* pcRecoYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion& ruiDistC, + Bool bLumaOnly + DEBUG_STRING_FN_DECLARE(sDebug)); + + Void estIntraPredChromaQT ( TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + TComYuv* pcRecoYuv, + Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE], + Distortion uiPreCalcDistC + DEBUG_STRING_FN_DECLARE(sDebug)); + + /// encoder estimation - inter prediction (non-skip) + Void predInterSearch ( TComDataCU* pcCU, + TComYuv* pcOrgYuv, + TComYuv* pcPredYuv, + TComYuv* pcResiYuv, + TComYuv* pcRecoYuv + DEBUG_STRING_FN_DECLARE(sDebug), + Bool bUseRes = false +#if AMP_MRG + ,Bool bUseMRG = false +#endif + ); + + /// encode residual and compute rd-cost for inter mode + Void encodeResAndCalcRdInterCU( TComDataCU* pcCU, + TComYuv* pcYuvOrg, + TComYuv* pcYuvPred, + TComYuv* pcYuvResi, + TComYuv* pcYuvResiBest, + TComYuv* pcYuvRec, + Bool bSkipRes + DEBUG_STRING_FN_DECLARE(sDebug) ); + + /// set ME search range + Void setAdaptiveSearchRange ( Int iDir, Int iRefIdx, Int iSearchRange) { assert(iDir < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdx + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TEncSlice::TEncSlice() +{ + m_apcPicYuvPred = NULL; + m_apcPicYuvResi = NULL; + + m_pdRdPicLambda = NULL; + m_pdRdPicQp = NULL; + m_piRdPicQp = NULL; +} + +TEncSlice::~TEncSlice() +{ +} + +Void TEncSlice::create( Int iWidth, Int iHeight, ChromaFormat chromaFormat, UInt iMaxCUWidth, UInt iMaxCUHeight, UChar uhTotalDepth ) +{ + // create prediction picture + if ( m_apcPicYuvPred == NULL ) + { + m_apcPicYuvPred = new TComPicYuv; + m_apcPicYuvPred->create( iWidth, iHeight, chromaFormat, iMaxCUWidth, iMaxCUHeight, uhTotalDepth ); + } + + // create residual picture + if( m_apcPicYuvResi == NULL ) + { + m_apcPicYuvResi = new TComPicYuv; + m_apcPicYuvResi->create( iWidth, iHeight, chromaFormat, iMaxCUWidth, iMaxCUHeight, uhTotalDepth ); + } +} + +Void TEncSlice::destroy() +{ + // destroy prediction picture + if ( m_apcPicYuvPred ) + { + m_apcPicYuvPred->destroy(); + delete m_apcPicYuvPred; + m_apcPicYuvPred = NULL; + } + + // destroy residual picture + if ( m_apcPicYuvResi ) + { + m_apcPicYuvResi->destroy(); + delete m_apcPicYuvResi; + m_apcPicYuvResi = NULL; + } + + // free lambda and QP arrays + if ( m_pdRdPicLambda ) { xFree( m_pdRdPicLambda ); m_pdRdPicLambda = NULL; } + if ( m_pdRdPicQp ) { xFree( m_pdRdPicQp ); m_pdRdPicQp = NULL; } + if ( m_piRdPicQp ) { xFree( m_piRdPicQp ); m_piRdPicQp = NULL; } +} + +Void TEncSlice::init( TEncTop* pcEncTop ) +{ + m_pcCfg = pcEncTop; + m_pcListPic = pcEncTop->getListPic(); + + m_pcGOPEncoder = pcEncTop->getGOPEncoder(); + m_pcCuEncoder = pcEncTop->getCuEncoder(); + m_pcPredSearch = pcEncTop->getPredSearch(); + + m_pcEntropyCoder = pcEncTop->getEntropyCoder(); + m_pcSbacCoder = pcEncTop->getSbacCoder(); + m_pcBinCABAC = pcEncTop->getBinCABAC(); + m_pcTrQuant = pcEncTop->getTrQuant(); + + m_pcRdCost = pcEncTop->getRdCost(); + m_pppcRDSbacCoder = pcEncTop->getRDSbacCoder(); + m_pcRDGoOnSbacCoder = pcEncTop->getRDGoOnSbacCoder(); + + // create lambda and QP arrays + m_pdRdPicLambda = (Double*)xMalloc( Double, m_pcCfg->getDeltaQpRD() * 2 + 1 ); + m_pdRdPicQp = (Double*)xMalloc( Double, m_pcCfg->getDeltaQpRD() * 2 + 1 ); + m_piRdPicQp = (Int* )xMalloc( Int, m_pcCfg->getDeltaQpRD() * 2 + 1 ); + m_pcRateCtrl = pcEncTop->getRateCtrl(); +} + + + +Void +TEncSlice::setUpLambda(TComSlice* slice, const Double dLambda, Int iQP) +{ + // store lambda + m_pcRdCost ->setLambda( dLambda ); + + // for RDO + // in RdCost there is only one lambda because the luma and chroma bits are not separated, instead we weight the distortion of chroma. + Double dLambdas[MAX_NUM_COMPONENT] = { dLambda }; + for(UInt compIdx=1; compIdxgetPPS()->getQpOffset(compID) + slice->getSliceChromaQpDelta(compID); + Int qpc=(iQP + chromaQPOffset < 0) ? iQP : getScaledChromaQP(iQP + chromaQPOffset, m_pcCfg->getChromaFormatIdc()); + Double tmpWeight = pow( 2.0, (iQP-qpc)/3.0 ); // takes into account of the chroma qp mapping and chroma qp Offset + m_pcRdCost->setDistortionWeight(compID, tmpWeight); + dLambdas[compIdx]=dLambda/tmpWeight; + } + +#if RDOQ_CHROMA_LAMBDA +// for RDOQ + m_pcTrQuant->setLambdas( dLambdas ); +#else + m_pcTrQuant->setLambda( dLambda ); +#endif + +// For SAO + slice ->setLambdas( dLambdas ); +} + + + +/** + - non-referenced frame marking + - QP computation based on temporal structure + - lambda computation based on QP + - set temporal layer ID and the parameter sets + . + \param pcPic picture class + \param pocLast POC of last picture + \param pocCurr current POC + \param iNumPicRcvd number of received pictures + \param iTimeOffset POC offset for hierarchical structure + \param iDepth temporal layer depth + \param rpcSlice slice header class + \param pSPS SPS associated with the slice + \param pPPS PPS associated with the slice + */ + +Void TEncSlice::initEncSlice( TComPic* pcPic, Int pocLast, Int pocCurr, Int iNumPicRcvd, Int iGOPid, TComSlice*& rpcSlice, TComSPS* pSPS, TComPPS *pPPS, Bool isField ) +{ + Double dQP; + Double dLambda; + + rpcSlice = pcPic->getSlice(0); + rpcSlice->setSPS( pSPS ); + rpcSlice->setPPS( pPPS ); + rpcSlice->setSliceBits(0); + rpcSlice->setPic( pcPic ); + rpcSlice->initSlice(); + rpcSlice->setPicOutputFlag( true ); + rpcSlice->setPOC( pocCurr ); + + // depth computation based on GOP size + Int depth; + { + Int poc = rpcSlice->getPOC(); + if(isField) + { + poc = (poc/2) % (m_pcCfg->getGOPSize()/2); + } + else + { + poc = poc % m_pcCfg->getGOPSize(); + } + + if ( poc == 0 ) + { + depth = 0; + } + else + { + Int step = m_pcCfg->getGOPSize(); + depth = 0; + for( Int i=step>>1; i>=1; i>>=1 ) + { + for ( Int j=i; jgetGOPSize(); j+=step ) + { + if ( j == poc ) + { + i=0; + break; + } + } + step >>= 1; + depth++; + } + } + +#if HARMONIZE_GOP_FIRST_FIELD_COUPLE + if(poc != 0) + { +#endif + if (isField && ((rpcSlice->getPOC() % 2) == 1)) + { + depth ++; + } +#if HARMONIZE_GOP_FIRST_FIELD_COUPLE + } +#endif + } + + // slice type + SliceType eSliceType; + + eSliceType=B_SLICE; +#if EFFICIENT_FIELD_IRAP + if(!(isField && pocLast == 1)) + { +#endif // EFFICIENT_FIELD_IRAP +#if ALLOW_RECOVERY_POINT_AS_RAP + if(m_pcCfg->getDecodingRefreshType() == 3) + { + eSliceType = (pocLast == 0 || pocCurr % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType; + } + else + { +#endif + eSliceType = (pocLast == 0 || (pocCurr - (isField ? 1 : 0)) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType; +#if ALLOW_RECOVERY_POINT_AS_RAP + } +#endif +#if EFFICIENT_FIELD_IRAP + } +#endif + + rpcSlice->setSliceType ( eSliceType ); + + // ------------------------------------------------------------------------------------------------------------------ + // Non-referenced frame marking + // ------------------------------------------------------------------------------------------------------------------ + + if(pocLast == 0) + { + rpcSlice->setTemporalLayerNonReferenceFlag(false); + } + else + { + rpcSlice->setTemporalLayerNonReferenceFlag(!m_pcCfg->getGOPEntry(iGOPid).m_refPic); + } + rpcSlice->setReferenced(true); + + // ------------------------------------------------------------------------------------------------------------------ + // QP setting + // ------------------------------------------------------------------------------------------------------------------ + + dQP = m_pcCfg->getQP(); + if(eSliceType!=I_SLICE) + { + if (!(( m_pcCfg->getMaxDeltaQP() == 0 ) && (dQP == -rpcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA) ) && (rpcSlice->getPPS()->getTransquantBypassEnableFlag()))) + { + dQP += m_pcCfg->getGOPEntry(iGOPid).m_QPOffset; + } + } + + // modify QP + Int* pdQPs = m_pcCfg->getdQPs(); + if ( pdQPs ) + { + dQP += pdQPs[ rpcSlice->getPOC() ]; + } + + if (m_pcCfg->getCostMode()==COST_LOSSLESS_CODING) + { + dQP=LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP; + m_pcCfg->setDeltaQpRD(0); + } + + // ------------------------------------------------------------------------------------------------------------------ + // Lambda computation + // ------------------------------------------------------------------------------------------------------------------ + + Int iQP; + Double dOrigQP = dQP; + + // pre-compute lambda and QP values for all possible QP candidates + for ( Int iDQpIdx = 0; iDQpIdx < 2 * m_pcCfg->getDeltaQpRD() + 1; iDQpIdx++ ) + { + // compute QP value + dQP = dOrigQP + ((iDQpIdx+1)>>1)*(iDQpIdx%2 ? -1 : 1); + + // compute lambda value + Int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 ); + Int SHIFT_QP = 12; + + Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)(isField ? NumberBFrames/2 : NumberBFrames) ); + +#if FULL_NBIT + Int bitdepth_luma_qp_scale = 6 * (g_bitDepth[CHANNEL_TYPE_LUMA] - 8); +#else + Int bitdepth_luma_qp_scale = 0; +#endif + Double qp_temp = (Double) dQP + bitdepth_luma_qp_scale - SHIFT_QP; +#if FULL_NBIT + Double qp_temp_orig = (Double) dQP - SHIFT_QP; +#endif + // Case #1: I or P-slices (key-frame) + Double dQPFactor = m_pcCfg->getGOPEntry(iGOPid).m_QPFactor; + if ( eSliceType==I_SLICE ) + { + dQPFactor=0.57*dLambda_scale; + } + dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 ); + + if ( depth>0 ) + { +#if FULL_NBIT + dLambda *= Clip3( 2.00, 4.00, (qp_temp_orig / 6.0) ); // (j == B_SLICE && p_cur_frm->layer != 0 ) +#else + dLambda *= Clip3( 2.00, 4.00, (qp_temp / 6.0) ); // (j == B_SLICE && p_cur_frm->layer != 0 ) +#endif + } + + // if hadamard is used in ME process + if ( !m_pcCfg->getUseHADME() && rpcSlice->getSliceType( ) != I_SLICE ) + { + dLambda *= 0.95; + } + + iQP = max( -pSPS->getQpBDOffset(CHANNEL_TYPE_LUMA), min( MAX_QP, (Int) floor( dQP + 0.5 ) ) ); + + m_pdRdPicLambda[iDQpIdx] = dLambda; + m_pdRdPicQp [iDQpIdx] = dQP; + m_piRdPicQp [iDQpIdx] = iQP; + } + + // obtain dQP = 0 case + dLambda = m_pdRdPicLambda[0]; + dQP = m_pdRdPicQp [0]; + iQP = m_piRdPicQp [0]; + + if( rpcSlice->getSliceType( ) != I_SLICE ) + { + dLambda *= m_pcCfg->getLambdaModifier( m_pcCfg->getGOPEntry(iGOPid).m_temporalId ); + } + + setUpLambda(rpcSlice, dLambda, iQP); + +#if HB_LAMBDA_FOR_LDC + // restore original slice type + +#if EFFICIENT_FIELD_IRAP + if(!(isField && pocLast == 1)) + { +#endif // EFFICIENT_FIELD_IRAP +#if ALLOW_RECOVERY_POINT_AS_RAP + if(m_pcCfg->getDecodingRefreshType() == 3) + { + eSliceType = (pocLast == 0 || (pocCurr) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType; + } + else + { +#endif + eSliceType = (pocLast == 0 || (pocCurr - (isField ? 1 : 0)) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType; +#if ALLOW_RECOVERY_POINT_AS_RAP + } +#endif +#if EFFICIENT_FIELD_IRAP + } +#endif // EFFICIENT_FIELD_IRAP + + rpcSlice->setSliceType ( eSliceType ); +#endif + + if (m_pcCfg->getUseRecalculateQPAccordingToLambda()) + { + dQP = xGetQPValueAccordingToLambda( dLambda ); + iQP = max( -pSPS->getQpBDOffset(CHANNEL_TYPE_LUMA), min( MAX_QP, (Int) floor( dQP + 0.5 ) ) ); + } + + rpcSlice->setSliceQp ( iQP ); +#if ADAPTIVE_QP_SELECTION + rpcSlice->setSliceQpBase ( iQP ); +#endif + rpcSlice->setSliceQpDelta ( 0 ); + rpcSlice->setSliceChromaQpDelta( COMPONENT_Cb, 0 ); + rpcSlice->setSliceChromaQpDelta( COMPONENT_Cr, 0 ); + rpcSlice->setUseChromaQpAdj( pPPS->getChromaQpAdjTableSize() > 0 ); + rpcSlice->setNumRefIdx(REF_PIC_LIST_0,m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive); + rpcSlice->setNumRefIdx(REF_PIC_LIST_1,m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive); + + if ( m_pcCfg->getDeblockingFilterMetric() ) + { + rpcSlice->setDeblockingFilterOverrideFlag(true); + rpcSlice->setDeblockingFilterDisable(false); + rpcSlice->setDeblockingFilterBetaOffsetDiv2( 0 ); + rpcSlice->setDeblockingFilterTcOffsetDiv2( 0 ); + } + else if (rpcSlice->getPPS()->getDeblockingFilterControlPresentFlag()) + { + rpcSlice->getPPS()->setDeblockingFilterOverrideEnabledFlag( !m_pcCfg->getLoopFilterOffsetInPPS() ); + rpcSlice->setDeblockingFilterOverrideFlag( !m_pcCfg->getLoopFilterOffsetInPPS() ); + rpcSlice->getPPS()->setPicDisableDeblockingFilterFlag( m_pcCfg->getLoopFilterDisable() ); + rpcSlice->setDeblockingFilterDisable( m_pcCfg->getLoopFilterDisable() ); + if ( !rpcSlice->getDeblockingFilterDisable()) + { + if ( !m_pcCfg->getLoopFilterOffsetInPPS() && eSliceType!=I_SLICE) + { + rpcSlice->getPPS()->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_betaOffsetDiv2 + m_pcCfg->getLoopFilterBetaOffset() ); + rpcSlice->getPPS()->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_tcOffsetDiv2 + m_pcCfg->getLoopFilterTcOffset() ); + rpcSlice->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_betaOffsetDiv2 + m_pcCfg->getLoopFilterBetaOffset() ); + rpcSlice->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_tcOffsetDiv2 + m_pcCfg->getLoopFilterTcOffset() ); + } + else + { + rpcSlice->getPPS()->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getLoopFilterBetaOffset() ); + rpcSlice->getPPS()->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getLoopFilterTcOffset() ); + rpcSlice->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getLoopFilterBetaOffset() ); + rpcSlice->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getLoopFilterTcOffset() ); + } + } + } + else + { + rpcSlice->setDeblockingFilterOverrideFlag( false ); + rpcSlice->setDeblockingFilterDisable( false ); + rpcSlice->setDeblockingFilterBetaOffsetDiv2( 0 ); + rpcSlice->setDeblockingFilterTcOffsetDiv2( 0 ); + } + + rpcSlice->setDepth ( depth ); + + pcPic->setTLayer( m_pcCfg->getGOPEntry(iGOPid).m_temporalId ); + if(eSliceType==I_SLICE) + { + pcPic->setTLayer(0); + } + rpcSlice->setTLayer( pcPic->getTLayer() ); + + assert( m_apcPicYuvPred ); + assert( m_apcPicYuvResi ); + + pcPic->setPicYuvPred( m_apcPicYuvPred ); + pcPic->setPicYuvResi( m_apcPicYuvResi ); + rpcSlice->setSliceMode ( m_pcCfg->getSliceMode() ); + rpcSlice->setSliceArgument ( m_pcCfg->getSliceArgument() ); + rpcSlice->setSliceSegmentMode ( m_pcCfg->getSliceSegmentMode() ); + rpcSlice->setSliceSegmentArgument ( m_pcCfg->getSliceSegmentArgument() ); + rpcSlice->setMaxNumMergeCand ( m_pcCfg->getMaxNumMergeCand() ); + xStoreWPparam( pPPS->getUseWP(), pPPS->getWPBiPred() ); +} + +Void TEncSlice::resetQP( TComPic* pic, Int sliceQP, Double lambda ) +{ + TComSlice* slice = pic->getSlice(0); + + // store lambda + slice->setSliceQp( sliceQP ); +#if ADAPTIVE_QP_SELECTION + slice->setSliceQpBase ( sliceQP ); +#endif + setUpLambda(slice, lambda, sliceQP); +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +Void TEncSlice::setSearchRange( TComSlice* pcSlice ) +{ + Int iCurrPOC = pcSlice->getPOC(); + Int iRefPOC; + Int iGOPSize = m_pcCfg->getGOPSize(); + Int iOffset = (iGOPSize >> 1); + Int iMaxSR = m_pcCfg->getSearchRange(); + Int iNumPredDir = pcSlice->isInterP() ? 1 : 2; + + for (Int iDir = 0; iDir <= iNumPredDir; iDir++) + { + //RefPicList e = (RefPicList)iDir; + RefPicList e = ( iDir ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); + for (Int iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(e); iRefIdx++) + { + iRefPOC = pcSlice->getRefPic(e, iRefIdx)->getPOC(); + Int iNewSR = Clip3(8, iMaxSR, (iMaxSR*ADAPT_SR_SCALE*abs(iCurrPOC - iRefPOC)+iOffset)/iGOPSize); + m_pcPredSearch->setAdaptiveSearchRange(iDir, iRefIdx, iNewSR); + } + } +} + +/** + - multi-loop slice encoding for different slice QP + . + \param rpcPic picture class + */ +Void TEncSlice::precompressSlice( TComPic* pcPic ) +{ + // if deltaQP RD is not used, simply return + if ( m_pcCfg->getDeltaQpRD() == 0 ) + { + return; + } + + if ( m_pcCfg->getUseRateCtrl() ) + { + printf( "\nMultiple QP optimization is not allowed when rate control is enabled." ); + assert(0); + } + + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + Double dPicRdCostBest = MAX_DOUBLE; + UInt uiQpIdxBest = 0; + + Double dFrameLambda; +#if FULL_NBIT + Int SHIFT_QP = 12 + 6 * (g_bitDepth[CHANNEL_TYPE_LUMA] - 8); +#else + Int SHIFT_QP = 12; +#endif + + // set frame lambda + if (m_pcCfg->getGOPSize() > 1) + { + dFrameLambda = 0.68 * pow (2, (m_piRdPicQp[0] - SHIFT_QP) / 3.0) * (pcSlice->isInterB()? 2 : 1); + } + else + { + dFrameLambda = 0.68 * pow (2, (m_piRdPicQp[0] - SHIFT_QP) / 3.0); + } + m_pcRdCost ->setFrameLambda(dFrameLambda); + + const UInt initialSliceQp=pcSlice->getSliceQp(); + // for each QP candidate + for ( UInt uiQpIdx = 0; uiQpIdx < 2 * m_pcCfg->getDeltaQpRD() + 1; uiQpIdx++ ) + { + pcSlice ->setSliceQp ( m_piRdPicQp [uiQpIdx] ); +#if ADAPTIVE_QP_SELECTION + pcSlice ->setSliceQpBase ( m_piRdPicQp [uiQpIdx] ); +#endif + setUpLambda(pcSlice, m_pdRdPicLambda[uiQpIdx], m_piRdPicQp [uiQpIdx]); + + // try compress + compressSlice ( pcPic ); + + Double dPicRdCost; + UInt64 uiPicDist = m_uiPicDist; + // TODO: will this work if multiple slices are being used? There may not be any reconstruction data yet. + // Will this also be ideal if a byte-restriction is placed on the slice? + // - what if the last CTU was sometimes included, sometimes not, and that had all the distortion? + m_pcGOPEncoder->preLoopFilterPicAll( pcPic, uiPicDist ); + + // compute RD cost and choose the best + dPicRdCost = m_pcRdCost->calcRdCost64( m_uiPicTotalBits, uiPicDist, true, DF_SSE_FRAME); + + if ( dPicRdCost < dPicRdCostBest ) + { + uiQpIdxBest = uiQpIdx; + dPicRdCostBest = dPicRdCost; + } + } + + if (pcSlice->getDependentSliceSegmentFlag() && initialSliceQp!=m_piRdPicQp[uiQpIdxBest] ) + { + // TODO: this won't work with dependent slices: they do not have their own QP. + fprintf(stderr,"ERROR - attempt to change QP for a dependent slice-segment, having already coded the slice\n"); + assert(pcSlice->getDependentSliceSegmentFlag()==false || initialSliceQp==m_piRdPicQp[uiQpIdxBest]); + } + // set best values + pcSlice ->setSliceQp ( m_piRdPicQp [uiQpIdxBest] ); +#if ADAPTIVE_QP_SELECTION + pcSlice ->setSliceQpBase ( m_piRdPicQp [uiQpIdxBest] ); +#endif + setUpLambda(pcSlice, m_pdRdPicLambda[uiQpIdxBest], m_piRdPicQp [uiQpIdxBest]); +} + +Void TEncSlice::calCostSliceI(TComPic* pcPic) +{ + UInt ctuRsAddr; + UInt startCtuTsAddr; + UInt boundingCtuTsAddr; + Int iSumHad, shift = g_bitDepth[CHANNEL_TYPE_LUMA]-8, offset = (shift>0)?(1<<(shift-1)):0;; + Double iSumHadSlice = 0; + + pcPic->getSlice(getSliceIdx())->setSliceSegmentBits(0); + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic, false ); + + UInt ctuTsAddr; + ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap( startCtuTsAddr); + for( ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(++ctuTsAddr) ) + { + // initialize CU encoder + TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); + pCtu->initCtu( pcPic, ctuRsAddr ); + + Int height = min( pcSlice->getSPS()->getMaxCUHeight(),pcSlice->getSPS()->getPicHeightInLumaSamples() - ctuRsAddr / pcPic->getFrameWidthInCtus() * pcSlice->getSPS()->getMaxCUHeight() ); + Int width = min( pcSlice->getSPS()->getMaxCUWidth(),pcSlice->getSPS()->getPicWidthInLumaSamples() - ctuRsAddr % pcPic->getFrameWidthInCtus() * pcSlice->getSPS()->getMaxCUWidth() ); + + iSumHad = m_pcCuEncoder->updateCtuDataISlice(pCtu, width, height); + + (m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_costIntra=(iSumHad+offset)>>shift; + iSumHadSlice += (m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_costIntra; + + } + m_pcRateCtrl->getRCPic()->setTotalIntraCost(iSumHadSlice); +} + +/** \param rpcPic picture class + */ +Void TEncSlice::compressSlice( TComPic* pcPic ) +{ + UInt startCtuTsAddr; + UInt boundingCtuTsAddr; + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + pcSlice->setSliceSegmentBits(0); + xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic, false ); + + // initialize cost values - these are used by precompressSlice (they should be parameters). + m_uiPicTotalBits = 0; + m_dPicRdCost = 0; // NOTE: This is a write-only variable! + m_uiPicDist = 0; + + m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST], pcSlice ); + m_pcEntropyCoder->resetEntropy (); + + TEncBinCABAC* pRDSbacCoder = (TEncBinCABAC *) m_pppcRDSbacCoder[0][CI_CURR_BEST]->getEncBinIf(); + pRDSbacCoder->setBinCountingEnableFlag( false ); + pRDSbacCoder->setBinsCoded( 0 ); + + TComBitCounter tempBitCounter; + const UInt frameWidthInCtus = pcPic->getPicSym()->getFrameWidthInCtus(); + + //------------------------------------------------------------------------------ + // Weighted Prediction parameters estimation. + //------------------------------------------------------------------------------ + // calculate AC/DC values for current picture + if( pcSlice->getPPS()->getUseWP() || pcSlice->getPPS()->getWPBiPred() ) + { + xCalcACDCParamSlice(pcSlice); + } + + const Bool bWp_explicit = (pcSlice->getSliceType()==P_SLICE && pcSlice->getPPS()->getUseWP()) || (pcSlice->getSliceType()==B_SLICE && pcSlice->getPPS()->getWPBiPred()); + + if ( bWp_explicit ) + { + //------------------------------------------------------------------------------ + // Weighted Prediction implemented at Slice level. SliceMode=2 is not supported yet. + //------------------------------------------------------------------------------ + if ( pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES || pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES ) + { + printf("Weighted Prediction is not supported with slice mode determined by max number of bins.\n"); exit(0); + } + + xEstimateWPParamSlice( pcSlice ); + pcSlice->initWpScaling(); + + // check WP on/off + xCheckWPEnable( pcSlice ); + } + +#if ADAPTIVE_QP_SELECTION + if( m_pcCfg->getUseAdaptQpSelect() && !(pcSlice->getDependentSliceSegmentFlag())) + { + // TODO: this won't work with dependent slices: they do not have their own QP. Check fix to mask clause execution with && !(pcSlice->getDependentSliceSegmentFlag()) + m_pcTrQuant->clearSliceARLCnt(); + if(pcSlice->getSliceType()!=I_SLICE) + { + Int qpBase = pcSlice->getSliceQpBase(); + pcSlice->setSliceQp(qpBase + m_pcTrQuant->getQpDelta(qpBase)); + } + } +#endif + + + + // Adjust initial state if this is the start of a dependent slice. + { + const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap( startCtuTsAddr); + const UInt currentTileIdx = pcPic->getPicSym()->getTileIdxMap(ctuRsAddr); + const TComTile *pCurrentTile = pcPic->getPicSym()->getTComTile(currentTileIdx); + const UInt firstCtuRsAddrOfTile = pCurrentTile->getFirstCtuRsAddr(); + if( pcSlice->getDependentSliceSegmentFlag() && ctuRsAddr != firstCtuRsAddrOfTile ) + { + // This will only occur if dependent slice-segments (m_entropyCodingSyncContextState=true) are being used. + if( pCurrentTile->getTileWidthInCtus() >= 2 || !m_pcCfg->getWaveFrontsynchro() ) + { + m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContexts( &m_lastSliceSegmentEndContextState ); + } + } + } + + // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment) + + for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr ) + { + const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(ctuTsAddr); + // initialize CTU encoder + TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); + pCtu->initCtu( pcPic, ctuRsAddr ); + + // update CABAC state + const UInt firstCtuRsAddrOfTile = pcPic->getPicSym()->getTComTile(pcPic->getPicSym()->getTileIdxMap(ctuRsAddr))->getFirstCtuRsAddr(); + const UInt tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus; + const UInt ctuXPosInCtus = ctuRsAddr % frameWidthInCtus; + + if (ctuRsAddr == firstCtuRsAddrOfTile) + { + m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetEntropy(); + } + else if ( ctuXPosInCtus == tileXPosInCtus && m_pcCfg->getWaveFrontsynchro()) + { + // reset and then update contexts to the state at the end of the top-right CTU (if within current slice and tile). + m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetEntropy(); + // Sync if the Top-Right is available. + TComDataCU *pCtuUp = pCtu->getCtuAbove(); + if ( pCtuUp && ((ctuRsAddr%frameWidthInCtus+1) < frameWidthInCtus) ) + { + TComDataCU *pCtuTR = pcPic->getCtu( ctuRsAddr - frameWidthInCtus + 1 ); + if ( pCtu->CUIsFromSameSliceAndTile(pCtuTR) ) + { + // Top-Right is available, we use it. + m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContexts( &m_entropyCodingSyncContextState ); + } + } + } + + // set go-on entropy coder (used for all trial encodings - the cu encoder and encoder search also have a copy of the same pointer) + m_pcEntropyCoder->setEntropyCoder ( m_pcRDGoOnSbacCoder, pcSlice ); + m_pcEntropyCoder->setBitstream( &tempBitCounter ); + tempBitCounter.resetBits(); + m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[0][CI_CURR_BEST] ); // this copy is not strictly necessary here, but indicates that the GoOnSbacCoder + // is reset to a known state before every decision process. + + ((TEncBinCABAC*)m_pcRDGoOnSbacCoder->getEncBinIf())->setBinCountingEnableFlag(true); + + Double oldLambda = m_pcRdCost->getLambda(); + if ( m_pcCfg->getUseRateCtrl() ) + { + Int estQP = pcSlice->getSliceQp(); + Double estLambda = -1.0; + Double bpp = -1.0; + + if ( ( pcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() ) + { + estQP = pcSlice->getSliceQp(); + } + else + { + bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType()); + if ( pcPic->getSlice( 0 )->getSliceType() == I_SLICE) + { + estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP); + } + else + { + estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp ); + estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() ); + } + + estQP = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, estQP ); + + m_pcRdCost->setLambda(estLambda); + +#if RDOQ_CHROMA_LAMBDA + // set lambda for RDOQ + const Double chromaLambda = estLambda / m_pcRdCost->getChromaWeight(); + const Double lambdaArray[MAX_NUM_COMPONENT] = { estLambda, chromaLambda, chromaLambda }; + m_pcTrQuant->setLambdas( lambdaArray ); +#else + m_pcTrQuant->setLambda( estLambda ); +#endif + } + + m_pcRateCtrl->setRCQP( estQP ); +#if ADAPTIVE_QP_SELECTION + pCtu->getSlice()->setSliceQpBase( estQP ); +#endif + } + + // run CTU trial encoder + m_pcCuEncoder->compressCtu( pCtu ); + + + // All CTU decisions have now been made. Restore entropy coder to an initial stage, ready to make a true encode, + // which will result in the state of the contexts being correct. It will also count up the number of bits coded, + // which is used if there is a limit of the number of bytes per slice-segment. + + m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST], pcSlice ); + m_pcEntropyCoder->setBitstream( &tempBitCounter ); + pRDSbacCoder->setBinCountingEnableFlag( true ); + m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetBits(); + pRDSbacCoder->setBinsCoded( 0 ); + + // encode CTU and calculate the true bit counters. + m_pcCuEncoder->encodeCtu( pCtu ); + + + pRDSbacCoder->setBinCountingEnableFlag( false ); + + const Int numberOfWrittenBits = m_pcEntropyCoder->getNumberOfWrittenBits(); + + // Calculate if this CTU puts us over slice bit size. + // cannot terminate if current slice/slice-segment would be 0 Ctu in size, + const UInt validEndOfSliceCtuTsAddr = ctuTsAddr + (ctuTsAddr == startCtuTsAddr ? 1 : 0); + // Set slice end parameter + if(pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES && pcSlice->getSliceBits()+numberOfWrittenBits > (pcSlice->getSliceArgument()<<3)) + { + pcSlice->setSliceSegmentCurEndCtuTsAddr(validEndOfSliceCtuTsAddr); + pcSlice->setSliceCurEndCtuTsAddr(validEndOfSliceCtuTsAddr); + boundingCtuTsAddr=validEndOfSliceCtuTsAddr; + } + else if(pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES && pcSlice->getSliceSegmentBits()+numberOfWrittenBits > (pcSlice->getSliceSegmentArgument()<<3)) + { + pcSlice->setSliceSegmentCurEndCtuTsAddr(validEndOfSliceCtuTsAddr); + boundingCtuTsAddr=validEndOfSliceCtuTsAddr; + } + + if (boundingCtuTsAddr <= ctuTsAddr) + break; + + pcSlice->setSliceBits( (UInt)(pcSlice->getSliceBits() + numberOfWrittenBits) ); + pcSlice->setSliceSegmentBits(pcSlice->getSliceSegmentBits()+numberOfWrittenBits); + + // Store probabilities of second CTU in line into buffer - used only if wavefront-parallel-processing is enabled. + if ( ctuXPosInCtus == tileXPosInCtus+1 && m_pcCfg->getWaveFrontsynchro()) + { + m_entropyCodingSyncContextState.loadContexts(m_pppcRDSbacCoder[0][CI_CURR_BEST]); + } + + + if ( m_pcCfg->getUseRateCtrl() ) + { + Int actualQP = g_RCInvalidQPValue; + Double actualLambda = m_pcRdCost->getLambda(); + Int actualBits = pCtu->getTotalBits(); + Int numberOfEffectivePixels = 0; + for ( Int idx = 0; idx < pcPic->getNumPartitionsInCtu(); idx++ ) + { + if ( pCtu->getPredictionMode( idx ) != NUMBER_OF_PREDICTION_MODES && ( !pCtu->isSkipped( idx ) ) ) + { + numberOfEffectivePixels = numberOfEffectivePixels + 16; + break; + } + } + + if ( numberOfEffectivePixels == 0 ) + { + actualQP = g_RCInvalidQPValue; + } + else + { + actualQP = pCtu->getQP( 0 ); + } + m_pcRdCost->setLambda(oldLambda); + m_pcRateCtrl->getRCPic()->updateAfterCTU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda, + pCtu->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() ); + } + + m_uiPicTotalBits += pCtu->getTotalBits(); + m_dPicRdCost += pCtu->getTotalCost(); + m_uiPicDist += pCtu->getTotalDistortion(); + } + + // store context state at the end of this slice-segment, in case the next slice is a dependent slice and continues using the CABAC contexts. + if( pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag() ) + { + m_lastSliceSegmentEndContextState.loadContexts( m_pppcRDSbacCoder[0][CI_CURR_BEST] );//ctx end of dep.slice + } + xRestoreWPparam( pcSlice ); + + // stop use of temporary bit counter object. + m_pppcRDSbacCoder[0][CI_CURR_BEST]->setBitstream(NULL); + m_pcRDGoOnSbacCoder->setBitstream(NULL); // stop use of tempBitCounter. +} + +/** + \param rpcPic picture class + \retval rpcBitstream bitstream class + */ +Void TEncSlice::encodeSlice ( TComPic* pcPic, TComOutputBitstream* pcSubstreams, UInt &numBinsCoded ) +{ + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + + const UInt startCtuTsAddr = pcSlice->getSliceSegmentCurStartCtuTsAddr(); + const UInt boundingCtuTsAddr = pcSlice->getSliceSegmentCurEndCtuTsAddr(); + + const UInt frameWidthInCtus = pcPic->getPicSym()->getFrameWidthInCtus(); + const Bool depSliceSegmentsEnabled = pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag(); + const Bool wavefrontsEnabled = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag(); + + // initialise entropy coder for the slice + m_pcSbacCoder->init( (TEncBinIf*)m_pcBinCABAC ); + m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice ); + m_pcEntropyCoder->resetEntropy (); + + numBinsCoded = 0; + m_pcBinCABAC->setBinCountingEnableFlag( true ); + m_pcBinCABAC->setBinsCoded(0); + +#if ENC_DEC_TRACE + g_bJustDoIt = g_bEncDecTraceEnable; +#endif + DTRACE_CABAC_VL( g_nSymbolCounter++ ); + DTRACE_CABAC_T( "\tPOC: " ); + DTRACE_CABAC_V( pcPic->getPOC() ); + DTRACE_CABAC_T( "\n" ); +#if ENC_DEC_TRACE + g_bJustDoIt = g_bEncDecTraceDisable; +#endif + + + if (depSliceSegmentsEnabled) + { + // modify initial contexts with previous slice segment if this is a dependent slice. + const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap( startCtuTsAddr ); + const UInt currentTileIdx=pcPic->getPicSym()->getTileIdxMap(ctuRsAddr); + const TComTile *pCurrentTile=pcPic->getPicSym()->getTComTile(currentTileIdx); + const UInt firstCtuRsAddrOfTile = pCurrentTile->getFirstCtuRsAddr(); + + if( pcSlice->getDependentSliceSegmentFlag() && ctuRsAddr != firstCtuRsAddrOfTile ) + { + if( pCurrentTile->getTileWidthInCtus() >= 2 || !wavefrontsEnabled ) + { + m_pcSbacCoder->loadContexts(&m_lastSliceSegmentEndContextState); + } + } + } + + // for every CTU in the slice segment... + + for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr ) + { + const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(ctuTsAddr); + const TComTile ¤tTile = *(pcPic->getPicSym()->getTComTile(pcPic->getPicSym()->getTileIdxMap(ctuRsAddr))); + const UInt firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); + const UInt tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus; + const UInt tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus; + const UInt ctuXPosInCtus = ctuRsAddr % frameWidthInCtus; + const UInt ctuYPosInCtus = ctuRsAddr / frameWidthInCtus; + const UInt uiSubStrm=pcPic->getSubstreamForCtuAddr(ctuRsAddr, true, pcSlice); + TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); + + m_pcEntropyCoder->setBitstream( &pcSubstreams[uiSubStrm] ); + + // set up CABAC contexts' state for this CTU + if (ctuRsAddr == firstCtuRsAddrOfTile) + { + if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset + { + m_pcEntropyCoder->resetEntropy(); + } + } + else if (ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled) + { + // Synchronize cabac probabilities with upper-right CTU if it's available and at the start of a line. + if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset + { + m_pcEntropyCoder->resetEntropy(); + } + TComDataCU *pCtuUp = pCtu->getCtuAbove(); + if ( pCtuUp && ((ctuRsAddr%frameWidthInCtus+1) < frameWidthInCtus) ) + { + TComDataCU *pCtuTR = pcPic->getCtu( ctuRsAddr - frameWidthInCtus + 1 ); + if ( pCtu->CUIsFromSameSliceAndTile(pCtuTR) ) + { + // Top-right is available, so use it. + m_pcSbacCoder->loadContexts( &m_entropyCodingSyncContextState ); + } + } + } + + + if ( pcSlice->getSPS()->getUseSAO() ) + { + Bool bIsSAOSliceEnabled = false; + Bool sliceEnabled[MAX_NUM_COMPONENT]; + for(Int comp=0; comp < MAX_NUM_COMPONENT; comp++) + { + ComponentID compId=ComponentID(comp); + sliceEnabled[compId] = pcSlice->getSaoEnabledFlag(toChannelType(compId)) && (comp < pcPic->getNumberValidComponents()); + if (sliceEnabled[compId]) bIsSAOSliceEnabled=true; + } + if (bIsSAOSliceEnabled) + { + SAOBlkParam& saoblkParam = (pcPic->getPicSym()->getSAOBlkParam())[ctuRsAddr]; + + Bool leftMergeAvail = false; + Bool aboveMergeAvail= false; + //merge left condition + Int rx = (ctuRsAddr % frameWidthInCtus); + if(rx > 0) + { + leftMergeAvail = pcPic->getSAOMergeAvailability(ctuRsAddr, ctuRsAddr-1); + } + + //merge up condition + Int ry = (ctuRsAddr / frameWidthInCtus); + if(ry > 0) + { + aboveMergeAvail = pcPic->getSAOMergeAvailability(ctuRsAddr, ctuRsAddr-frameWidthInCtus); + } + + m_pcEntropyCoder->encodeSAOBlkParam(saoblkParam, sliceEnabled, leftMergeAvail, aboveMergeAvail); + } + } + +#if ENC_DEC_TRACE + g_bJustDoIt = g_bEncDecTraceEnable; +#endif + m_pcCuEncoder->encodeCtu( pCtu ); +#if ENC_DEC_TRACE + g_bJustDoIt = g_bEncDecTraceDisable; +#endif + + //Store probabilities of second CTU in line into buffer + if ( ctuXPosInCtus == tileXPosInCtus+1 && wavefrontsEnabled) + { + m_entropyCodingSyncContextState.loadContexts( m_pcSbacCoder ); + } + + // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row): + if (ctuTsAddr+1 == boundingCtuTsAddr || + ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus() && + ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled) + ) + ) + { + m_pcEntropyCoder->encodeTerminatingBit(1); + m_pcEntropyCoder->encodeSliceFinish(); + // Byte-alignment in slice_data() when new tile + pcSubstreams[uiSubStrm].writeByteAlignment(); + + // write sub-stream size + if (ctuTsAddr+1 != boundingCtuTsAddr) + { + pcSlice->addSubstreamSize( (pcSubstreams[uiSubStrm].getNumberOfWrittenBits() >> 3) + pcSubstreams[uiSubStrm].countStartCodeEmulations() ); + } + } + } // CTU-loop + + if( depSliceSegmentsEnabled ) + { + m_lastSliceSegmentEndContextState.loadContexts( m_pcSbacCoder );//ctx end of dep.slice + } + +#if ADAPTIVE_QP_SELECTION + if( m_pcCfg->getUseAdaptQpSelect() ) + { + m_pcTrQuant->storeSliceQpNext(pcSlice); + } +#endif + + if (pcSlice->getPPS()->getCabacInitPresentFlag()) + { + if (pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag()) + { + pcSlice->getPPS()->setEncCABACTableIdx( pcSlice->getSliceType() ); + } + else + { + m_pcEntropyCoder->determineCabacInitIdx(); + } + } + numBinsCoded = m_pcBinCABAC->getBinsCoded(); +} + +Void TEncSlice::calculateBoundingCtuTsAddrForSlice(UInt &startCtuTSAddrSlice, UInt &boundingCtuTSAddrSlice, Bool &haveReachedTileBoundary, + TComPic* pcPic, const Bool encodingSlice, const Int sliceMode, const Int sliceArgument, const UInt sliceCurEndCtuTSAddr) +{ + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + const UInt numberOfCtusInFrame = pcPic->getNumberOfCtusInFrame(); + boundingCtuTSAddrSlice=0; + haveReachedTileBoundary=false; + + switch (sliceMode) + { + case FIXED_NUMBER_OF_CTU: + { + UInt ctuAddrIncrement = sliceArgument; + boundingCtuTSAddrSlice = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame; + } + break; + case FIXED_NUMBER_OF_BYTES: + if (encodingSlice) + boundingCtuTSAddrSlice = sliceCurEndCtuTSAddr; + else + boundingCtuTSAddrSlice = numberOfCtusInFrame; + break; + case FIXED_NUMBER_OF_TILES: + { + const UInt tileIdx = pcPic->getPicSym()->getTileIdxMap( pcPic->getPicSym()->getCtuTsToRsAddrMap(startCtuTSAddrSlice) ); + const UInt tileTotalCount = (pcPic->getPicSym()->getNumTileColumnsMinus1()+1) * (pcPic->getPicSym()->getNumTileRowsMinus1()+1); + UInt ctuAddrIncrement = 0; + + for(UInt tileIdxIncrement = 0; tileIdxIncrement < sliceArgument; tileIdxIncrement++) + { + if((tileIdx + tileIdxIncrement) < tileTotalCount) + { + UInt tileWidthInCtus = pcPic->getPicSym()->getTComTile(tileIdx + tileIdxIncrement)->getTileWidthInCtus(); + UInt tileHeightInCtus = pcPic->getPicSym()->getTComTile(tileIdx + tileIdxIncrement)->getTileHeightInCtus(); + ctuAddrIncrement += (tileWidthInCtus * tileHeightInCtus); + } + } + + boundingCtuTSAddrSlice = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame; + } + break; + default: + boundingCtuTSAddrSlice = numberOfCtusInFrame; + break; + } + + // Adjust for tiles and wavefronts. + if ((sliceMode == FIXED_NUMBER_OF_CTU || sliceMode == FIXED_NUMBER_OF_BYTES) && + (m_pcCfg->getNumRowsMinus1() > 0 || m_pcCfg->getNumColumnsMinus1() > 0)) + { + const UInt ctuRSAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(startCtuTSAddrSlice); + const UInt startTileIdx = pcPic->getPicSym()->getTileIdxMap(ctuRSAddr); + const Bool wavefrontsAreEnabled = m_pcCfg->getWaveFrontsynchro(); + + const TComTile *pStartingTile = pcPic->getPicSym()->getTComTile(startTileIdx); + const UInt tileStartTsAddr = pcPic->getPicSym()->getCtuRsToTsAddrMap(pStartingTile->getFirstCtuRsAddr()); + const UInt tileStartWidth = pStartingTile->getTileWidthInCtus(); + const UInt tileStartHeight = pStartingTile->getTileHeightInCtus(); + const UInt tileLastTsAddr_excl = tileStartTsAddr + tileStartWidth*tileStartHeight; + const UInt tileBoundingCtuTsAddrSlice = tileLastTsAddr_excl; + + const UInt ctuColumnOfStartingTile = ((startCtuTSAddrSlice-tileStartTsAddr)%tileStartWidth); + if (wavefrontsAreEnabled && ctuColumnOfStartingTile!=0) + { + // WPP: if a slice does not start at the beginning of a CTB row, it must end within the same CTB row + const UInt numberOfCTUsToEndOfRow = tileStartWidth - ctuColumnOfStartingTile; + const UInt wavefrontTileBoundingCtuAddrSlice = startCtuTSAddrSlice + numberOfCTUsToEndOfRow; + if (wavefrontTileBoundingCtuAddrSlice < boundingCtuTSAddrSlice) + { + boundingCtuTSAddrSlice = wavefrontTileBoundingCtuAddrSlice; + } + } + + if (tileBoundingCtuTsAddrSlice < boundingCtuTSAddrSlice) + { + boundingCtuTSAddrSlice = tileBoundingCtuTsAddrSlice; + haveReachedTileBoundary = true; + } + } + else if ((sliceMode == FIXED_NUMBER_OF_CTU || sliceMode == FIXED_NUMBER_OF_BYTES) && pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() && ((startCtuTSAddrSlice % pcPic->getFrameWidthInCtus()) != 0)) + { + // Adjust for wavefronts (no tiles). + // WPP: if a slice does not start at the beginning of a CTB row, it must end within the same CTB row + boundingCtuTSAddrSlice = min(boundingCtuTSAddrSlice, startCtuTSAddrSlice - (startCtuTSAddrSlice % pcPic->getFrameWidthInCtus()) + (pcPic->getFrameWidthInCtus())); + } +} + +/** Determines the starting and bounding CTU address of current slice / dependent slice + * \param bEncodeSlice Identifies if the calling function is compressSlice() [false] or encodeSlice() [true] + * \returns Updates startCtuTsAddr, boundingCtuTsAddr with appropriate CTU address + */ +Void TEncSlice::xDetermineStartAndBoundingCtuTsAddr ( UInt& startCtuTsAddr, UInt& boundingCtuTsAddr, TComPic* pcPic, const Bool encodingSlice ) +{ + TComSlice* pcSlice = pcPic->getSlice(getSliceIdx()); + + // Non-dependent slice + UInt startCtuTsAddrSlice = pcSlice->getSliceCurStartCtuTsAddr(); + Bool haveReachedTileBoundarySlice = false; + UInt boundingCtuTsAddrSlice; + calculateBoundingCtuTsAddrForSlice(startCtuTsAddrSlice, boundingCtuTsAddrSlice, haveReachedTileBoundarySlice, pcPic, + encodingSlice, m_pcCfg->getSliceMode(), m_pcCfg->getSliceArgument(), pcSlice->getSliceCurEndCtuTsAddr()); + pcSlice->setSliceCurEndCtuTsAddr( boundingCtuTsAddrSlice ); + pcSlice->setSliceCurStartCtuTsAddr( startCtuTsAddrSlice ); + + // Dependent slice + UInt startCtuTsAddrSliceSegment = pcSlice->getSliceSegmentCurStartCtuTsAddr(); + Bool haveReachedTileBoundarySliceSegment = false; + UInt boundingCtuTsAddrSliceSegment; + calculateBoundingCtuTsAddrForSlice(startCtuTsAddrSliceSegment, boundingCtuTsAddrSliceSegment, haveReachedTileBoundarySliceSegment, pcPic, + encodingSlice, m_pcCfg->getSliceSegmentMode(), m_pcCfg->getSliceSegmentArgument(), pcSlice->getSliceSegmentCurEndCtuTsAddr()); + if (boundingCtuTsAddrSliceSegment>boundingCtuTsAddrSlice) + { + boundingCtuTsAddrSliceSegment = boundingCtuTsAddrSlice; + } + pcSlice->setSliceSegmentCurEndCtuTsAddr( boundingCtuTsAddrSliceSegment ); + pcSlice->setSliceSegmentCurStartCtuTsAddr(startCtuTsAddrSliceSegment); + + // Make a joint decision based on reconstruction and dependent slice bounds + startCtuTsAddr = max(startCtuTsAddrSlice , startCtuTsAddrSliceSegment ); + boundingCtuTsAddr = boundingCtuTsAddrSliceSegment; +} + +Double TEncSlice::xGetQPValueAccordingToLambda ( Double lambda ) +{ + return 4.2005*log(lambda) + 13.7122; +} + +//! \} diff --git a/jctvc/TLibEncoder/TEncSlice.h b/jctvc/TLibEncoder/TEncSlice.h new file mode 100644 index 0000000..a4d992c --- /dev/null +++ b/jctvc/TLibEncoder/TEncSlice.h @@ -0,0 +1,136 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncSlice.h + \brief slice encoder class (header) +*/ + +#ifndef __TENCSLICE__ +#define __TENCSLICE__ + +// Include files +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComList.h" +#include "TLibCommon/TComPic.h" +#include "TLibCommon/TComPicYuv.h" +#include "TEncCu.h" +#include "WeightPredAnalysis.h" +#include "TEncRateCtrl.h" + +//! \ingroup TLibEncoder +//! \{ + +class TEncTop; +class TEncGOP; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// slice encoder class +class TEncSlice + : public WeightPredAnalysis +{ +private: + // encoder configuration + TEncCfg* m_pcCfg; ///< encoder configuration class + + // pictures + TComList* m_pcListPic; ///< list of pictures + TComPicYuv* m_apcPicYuvPred; ///< prediction picture buffer + TComPicYuv* m_apcPicYuvResi; ///< residual picture buffer + + // processing units + TEncGOP* m_pcGOPEncoder; ///< GOP encoder + TEncCu* m_pcCuEncoder; ///< CU encoder + + // encoder search + TEncSearch* m_pcPredSearch; ///< encoder search class + + // coding tools + TEncEntropy* m_pcEntropyCoder; ///< entropy encoder + TEncSbac* m_pcSbacCoder; ///< SBAC encoder + TEncBinCABAC* m_pcBinCABAC; ///< Bin encoder CABAC + TComTrQuant* m_pcTrQuant; ///< transform & quantization + + // RD optimization + TComRdCost* m_pcRdCost; ///< RD cost computation + TEncSbac*** m_pppcRDSbacCoder; ///< storage for SBAC-based RD optimization + TEncSbac* m_pcRDGoOnSbacCoder; ///< go-on SBAC encoder + UInt64 m_uiPicTotalBits; ///< total bits for the picture + UInt64 m_uiPicDist; ///< total distortion for the picture + Double m_dPicRdCost; ///< picture-level RD cost + Double* m_pdRdPicLambda; ///< array of lambda candidates + Double* m_pdRdPicQp; ///< array of picture QP candidates (double-type for lambda) + Int* m_piRdPicQp; ///< array of picture QP candidates (Int-type) + TEncRateCtrl* m_pcRateCtrl; ///< Rate control manager + UInt m_uiSliceIdx; + TEncSbac m_lastSliceSegmentEndContextState; ///< context storage for state at the end of the previous slice-segment (used for dependent slices only). + TEncSbac m_entropyCodingSyncContextState; ///< context storate for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row + + Void setUpLambda(TComSlice* slice, const Double dLambda, Int iQP); + Void calculateBoundingCtuTsAddrForSlice(UInt &startCtuTSAddrSlice, UInt &boundingCtuTSAddrSlice, Bool &haveReachedTileBoundary, TComPic* pcPic, const Bool encodingSlice, const Int sliceMode, const Int sliceArgument, const UInt uiSliceCurEndCtuTSAddr); + +public: + TEncSlice(); + virtual ~TEncSlice(); + + Void create ( Int iWidth, Int iHeight, ChromaFormat chromaFormat, UInt iMaxCUWidth, UInt iMaxCUHeight, UChar uhTotalDepth ); + Void destroy (); + Void init ( TEncTop* pcEncTop ); + + /// preparation of slice encoding (reference marking, QP and lambda) + Void initEncSlice ( TComPic* pcPic, Int pocLast, Int pocCurr, Int iNumPicRcvd, + Int iGOPid, TComSlice*& rpcSlice, TComSPS* pSPS, TComPPS *pPPS, Bool isField ); + Void resetQP ( TComPic* pic, Int sliceQP, Double lambda ); + // compress and encode slice + Void precompressSlice ( TComPic* pcPic ); ///< precompress slice for multi-loop opt. + Void compressSlice ( TComPic* pcPic ); ///< analysis stage of slice + Void calCostSliceI ( TComPic* pcPic ); + Void encodeSlice ( TComPic* pcPic, TComOutputBitstream* pcSubstreams, UInt &numBinsCoded ); + + // misc. functions + Void setSearchRange ( TComSlice* pcSlice ); ///< set ME range adaptively + + TEncCu* getCUEncoder() { return m_pcCuEncoder; } ///< CU encoder + Void xDetermineStartAndBoundingCtuTsAddr ( UInt& startCtuTsAddr, UInt& boundingCtuTsAddr, TComPic* pcPic, const Bool encodingSlice ); + UInt getSliceIdx() { return m_uiSliceIdx; } + Void setSliceIdx(UInt i) { m_uiSliceIdx = i; } + +private: + Double xGetQPValueAccordingToLambda ( Double lambda ); +}; + +//! \} + +#endif // __TENCSLICE__ diff --git a/jctvc/TLibEncoder/TEncTop.cpp b/jctvc/TLibEncoder/TEncTop.cpp new file mode 100644 index 0000000..d696348 --- /dev/null +++ b/jctvc/TLibEncoder/TEncTop.cpp @@ -0,0 +1,1056 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncTop.cpp + \brief encoder class +*/ + +#include "TLibCommon/CommonDef.h" +#include "TEncTop.h" +#include "TEncPic.h" +#include "TLibCommon/TComChromaFormat.h" +#if FAST_BIT_EST +#include "TLibCommon/ContextModel.h" +#endif + +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +TEncTop::TEncTop() +{ + m_iPOCLast = -1; + m_iNumPicRcvd = 0; + m_uiNumAllPicCoded = 0; + m_pppcRDSbacCoder = NULL; + m_pppcBinCoderCABAC = NULL; + m_cRDGoOnSbacCoder.init( &m_cRDGoOnBinCoderCABAC ); +#if ENC_DEC_TRACE + if (g_hTrace == NULL) + { + g_hTrace = fopen( "TraceEnc.txt", "wb" ); + } + g_bJustDoIt = g_bEncDecTraceDisable; + g_nSymbolCounter = 0; +#endif + + m_iMaxRefPicNum = 0; + +#if FAST_BIT_EST + ContextModel::buildNextStateTable(); +#endif +} + +TEncTop::~TEncTop() +{ +#if ENC_DEC_TRACE + if (g_hTrace != stdout) + { + fclose( g_hTrace ); + } +#endif +} + +Void TEncTop::create () +{ + // initialize global variables + initROM(); + + // create processing unit classes + m_cGOPEncoder. create( ); + m_cSliceEncoder. create( getSourceWidth(), getSourceHeight(), m_chromaFormatIDC, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth ); + m_cCuEncoder. create( g_uiMaxCUDepth, g_uiMaxCUWidth, g_uiMaxCUHeight, m_chromaFormatIDC ); + if (m_bUseSAO) + { + m_cEncSAO.create( getSourceWidth(), getSourceHeight(), m_chromaFormatIDC, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth, m_saoOffsetBitShift[CHANNEL_TYPE_LUMA], m_saoOffsetBitShift[CHANNEL_TYPE_CHROMA] ); +#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK + m_cEncSAO.createEncData(getSaoCtuBoundary()); +#else + m_cEncSAO.createEncData(); +#endif + } +#if ADAPTIVE_QP_SELECTION + if (m_bUseAdaptQpSelect) + { + m_cTrQuant.initSliceQpDelta(); + } +#endif + + m_cLoopFilter.create( g_uiMaxCUDepth ); + + if ( m_RCEnableRateControl ) + { + m_cRateCtrl.init( m_framesToBeEncoded, m_RCTargetBitrate, m_iFrameRate, m_iGOPSize, m_iSourceWidth, m_iSourceHeight, + g_uiMaxCUWidth, g_uiMaxCUHeight, m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList ); + } + + m_pppcRDSbacCoder = new TEncSbac** [g_uiMaxCUDepth+1]; +#if FAST_BIT_EST + m_pppcBinCoderCABAC = new TEncBinCABACCounter** [g_uiMaxCUDepth+1]; +#else + m_pppcBinCoderCABAC = new TEncBinCABAC** [g_uiMaxCUDepth+1]; +#endif + + for ( Int iDepth = 0; iDepth < g_uiMaxCUDepth+1; iDepth++ ) + { + m_pppcRDSbacCoder[iDepth] = new TEncSbac* [CI_NUM]; +#if FAST_BIT_EST + m_pppcBinCoderCABAC[iDepth] = new TEncBinCABACCounter* [CI_NUM]; +#else + m_pppcBinCoderCABAC[iDepth] = new TEncBinCABAC* [CI_NUM]; +#endif + + for (Int iCIIdx = 0; iCIIdx < CI_NUM; iCIIdx ++ ) + { + m_pppcRDSbacCoder[iDepth][iCIIdx] = new TEncSbac; +#if FAST_BIT_EST + m_pppcBinCoderCABAC [iDepth][iCIIdx] = new TEncBinCABACCounter; +#else + m_pppcBinCoderCABAC [iDepth][iCIIdx] = new TEncBinCABAC; +#endif + m_pppcRDSbacCoder [iDepth][iCIIdx]->init( m_pppcBinCoderCABAC [iDepth][iCIIdx] ); + } + } +} + +Void TEncTop::destroy () +{ + // destroy processing unit classes + m_cGOPEncoder. destroy(); + m_cSliceEncoder. destroy(); + m_cCuEncoder. destroy(); + if (m_cSPS.getUseSAO()) + { + m_cEncSAO.destroyEncData(); + m_cEncSAO.destroy(); + } + m_cLoopFilter. destroy(); + m_cRateCtrl. destroy(); + Int iDepth; + for ( iDepth = 0; iDepth < g_uiMaxCUDepth+1; iDepth++ ) + { + for (Int iCIIdx = 0; iCIIdx < CI_NUM; iCIIdx ++ ) + { + delete m_pppcRDSbacCoder[iDepth][iCIIdx]; + delete m_pppcBinCoderCABAC[iDepth][iCIIdx]; + } + } + + for ( iDepth = 0; iDepth < g_uiMaxCUDepth+1; iDepth++ ) + { + delete [] m_pppcRDSbacCoder[iDepth]; + delete [] m_pppcBinCoderCABAC[iDepth]; + } + + delete [] m_pppcRDSbacCoder; + delete [] m_pppcBinCoderCABAC; + + // destroy ROM + destroyROM(); + + return; +} + +Void TEncTop::init(Bool isFieldCoding) +{ + // initialize SPS + xInitSPS(); + + // set the VPS profile information + *m_cVPS.getPTL() = *m_cSPS.getPTL(); + m_cVPS.getTimingInfo()->setTimingInfoPresentFlag ( false ); + + m_cRdCost.setCostMode(m_costMode); + + // initialize PPS + m_cPPS.setSPS(&m_cSPS); + xInitPPS(); + xInitRPS(isFieldCoding); + + xInitPPSforTiles(); + + // initialize processing unit classes + m_cGOPEncoder. init( this ); + m_cSliceEncoder.init( this ); + m_cCuEncoder. init( this ); + + // initialize transform & quantization class + m_pcCavlcCoder = getCavlcCoder(); + + m_cTrQuant.init( 1 << m_uiQuadtreeTULog2MaxSize, + m_useRDOQ, + m_useRDOQTS, + true + ,m_useTransformSkipFast +#if ADAPTIVE_QP_SELECTION + ,m_bUseAdaptQpSelect +#endif + ); + + // initialize encoder search class + m_cSearch.init( this, &m_cTrQuant, m_iSearchRange, m_bipredSearchRange, m_iFastSearch, 0, &m_cEntropyCoder, &m_cRdCost, getRDSbacCoder(), getRDGoOnSbacCoder() ); + + m_iMaxRefPicNum = 0; +} + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +Void TEncTop::deletePicBuffer() +{ + TComList::iterator iterPic = m_cListPic.begin(); + Int iSize = Int( m_cListPic.size() ); + + for ( Int i = 0; i < iSize; i++ ) + { + TComPic* pcPic = *(iterPic++); + + pcPic->destroy(); + delete pcPic; + pcPic = NULL; + } +} + +/** + - Application has picture buffer list with size of GOP + 1 + - Picture buffer list acts like as ring buffer + - End of the list has the latest picture + . + \param flush cause encoder to encode a partial GOP + \param pcPicYuvOrg original YUV picture + \retval rcListPicYuvRecOut list of reconstruction YUV pictures + \retval rcListBitstreamOut list of output bitstreams + \retval iNumEncoded number of encoded pictures + */ +Void TEncTop::encode( Bool flush, TComPicYuv* pcPicYuvOrg, TComPicYuv* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, TComList& rcListPicYuvRecOut, std::list& accessUnitsOut, Int& iNumEncoded ) +{ + if (pcPicYuvOrg != NULL) + { + // get original YUV + TComPic* pcPicCurr = NULL; + + xGetNewPicBuffer( pcPicCurr ); + pcPicYuvOrg->copyToPic( pcPicCurr->getPicYuvOrg() ); + pcPicYuvTrueOrg->copyToPic( pcPicCurr->getPicYuvTrueOrg() ); + + // compute image characteristics + if ( getUseAdaptiveQP() ) + { + m_cPreanalyzer.xPreanalyze( dynamic_cast( pcPicCurr ) ); + } + } + + if ((m_iNumPicRcvd == 0) || (!flush && (m_iPOCLast != 0) && (m_iNumPicRcvd != m_iGOPSize) && (m_iGOPSize != 0))) + { + iNumEncoded = 0; + return; + } + + if ( m_RCEnableRateControl ) + { + m_cRateCtrl.initRCGOP( m_iNumPicRcvd ); + } + + // compress GOP + m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut, false, false, snrCSC, m_printFrameMSE); + + if ( m_RCEnableRateControl ) + { + m_cRateCtrl.destroyRCGOP(); + } + + iNumEncoded = m_iNumPicRcvd; + m_iNumPicRcvd = 0; + m_uiNumAllPicCoded += iNumEncoded; +} + +/**------------------------------------------------ + Separate interlaced frame into two fields + -------------------------------------------------**/ +Void separateFields(Pel* org, Pel* dstField, UInt stride, UInt width, UInt height, Bool isTop) +{ + if (!isTop) + { + org += stride; + } + for (Int y = 0; y < height>>1; y++) + { + for (Int x = 0; x < width; x++) + { + dstField[x] = org[x]; + } + + dstField += stride; + org += stride*2; + } + +} + +Void TEncTop::encode(Bool flush, TComPicYuv* pcPicYuvOrg, TComPicYuv* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, TComList& rcListPicYuvRecOut, std::list& accessUnitsOut, Int& iNumEncoded, Bool isTff) +{ + iNumEncoded = 0; + + for (Int fieldNum=0; fieldNum<2; fieldNum++) + { + if (pcPicYuvOrg) + { + + /* -- field initialization -- */ + const Bool isTopField=isTff==(fieldNum==0); + + TComPic *pcField; + xGetNewPicBuffer( pcField ); + pcField->setReconMark (false); // where is this normally? + + if (fieldNum==1) // where is this normally? + { + TComPicYuv* rpcPicYuvRec; + + // org. buffer + if ( rcListPicYuvRecOut.size() >= (UInt)m_iGOPSize+1 ) // need to maintain field 0 in list of RecOuts while processing field 1. Hence +1 on m_iGOPSize. + { + rpcPicYuvRec = rcListPicYuvRecOut.popFront(); + } + else + { + rpcPicYuvRec = new TComPicYuv; + rpcPicYuvRec->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); + } + rcListPicYuvRecOut.pushBack( rpcPicYuvRec ); + } + + pcField->getSlice(0)->setPOC( m_iPOCLast ); // superfluous? + pcField->getPicYuvRec()->setBorderExtension(false);// where is this normally? + + pcField->setTopField(isTopField); // interlaced requirement + + for (UInt componentIndex = 0; componentIndex < pcPicYuvOrg->getNumberValidComponents(); componentIndex++) + { + const ComponentID component = ComponentID(componentIndex); + const UInt stride = pcPicYuvOrg->getStride(component); + + separateFields((pcPicYuvOrg->getBuf(component) + pcPicYuvOrg->getMarginX(component) + (pcPicYuvOrg->getMarginY(component) * stride)), + pcField->getPicYuvOrg()->getAddr(component), + pcPicYuvOrg->getStride(component), + pcPicYuvOrg->getWidth(component), + pcPicYuvOrg->getHeight(component), + isTopField); + + separateFields((pcPicYuvTrueOrg->getBuf(component) + pcPicYuvTrueOrg->getMarginX(component) + (pcPicYuvTrueOrg->getMarginY(component) * stride)), + pcField->getPicYuvTrueOrg()->getAddr(component), + pcPicYuvTrueOrg->getStride(component), + pcPicYuvTrueOrg->getWidth(component), + pcPicYuvTrueOrg->getHeight(component), + isTopField); + } + + // compute image characteristics + if ( getUseAdaptiveQP() ) + { + m_cPreanalyzer.xPreanalyze( dynamic_cast( pcField ) ); + } + } + + if ( m_iNumPicRcvd && ((flush&&fieldNum==1) || (m_iPOCLast/2)==0 || m_iNumPicRcvd==m_iGOPSize ) ) + { + // compress GOP + m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut, true, isTff, snrCSC, m_printFrameMSE); + + iNumEncoded += m_iNumPicRcvd; + m_uiNumAllPicCoded += m_iNumPicRcvd; + m_iNumPicRcvd = 0; + } + } +} + +// ==================================================================================================================== +// Protected member functions +// ==================================================================================================================== + +/** + - Application has picture buffer list with size of GOP + 1 + - Picture buffer list acts like as ring buffer + - End of the list has the latest picture + . + \retval rpcPic obtained picture buffer + */ +Void TEncTop::xGetNewPicBuffer ( TComPic*& rpcPic ) +{ + TComSlice::sortPicList(m_cListPic); + + if (m_cListPic.size() >= (UInt)(m_iGOPSize + getMaxDecPicBuffering(MAX_TLAYER-1) + 2) ) + { + TComList::iterator iterPic = m_cListPic.begin(); + Int iSize = Int( m_cListPic.size() ); + for ( Int i = 0; i < iSize; i++ ) + { + rpcPic = *(iterPic++); + if(rpcPic->getSlice(0)->isReferenced() == false) + { + break; + } + } + } + else + { + if ( getUseAdaptiveQP() ) + { + TEncPic* pcEPic = new TEncPic; + pcEPic->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth, m_cPPS.getMaxCuDQPDepth()+1, m_conformanceWindow, m_defaultDisplayWindow, m_numReorderPics); + rpcPic = pcEPic; + } + else + { + rpcPic = new TComPic; + rpcPic->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth, m_conformanceWindow, m_defaultDisplayWindow, m_numReorderPics, false ); + } + + m_cListPic.pushBack( rpcPic ); + } + rpcPic->setReconMark (false); + + m_iPOCLast++; + m_iNumPicRcvd++; + + rpcPic->getSlice(0)->setPOC( m_iPOCLast ); + // mark it should be extended + rpcPic->getPicYuvRec()->setBorderExtension(false); +} + +Void TEncTop::xInitSPS() +{ + ProfileTierLevel& profileTierLevel = *m_cSPS.getPTL()->getGeneralPTL(); + profileTierLevel.setLevelIdc(m_level); + profileTierLevel.setTierFlag(m_levelTier); + profileTierLevel.setProfileIdc(m_profile); + profileTierLevel.setProfileCompatibilityFlag(m_profile, 1); + profileTierLevel.setProgressiveSourceFlag(m_progressiveSourceFlag); + profileTierLevel.setInterlacedSourceFlag(m_interlacedSourceFlag); + profileTierLevel.setNonPackedConstraintFlag(m_nonPackedConstraintFlag); + profileTierLevel.setFrameOnlyConstraintFlag(m_frameOnlyConstraintFlag); + profileTierLevel.setBitDepthConstraint(m_bitDepthConstraintValue); + profileTierLevel.setChromaFormatConstraint(m_chromaFormatConstraintValue); + profileTierLevel.setIntraConstraintFlag(m_intraConstraintFlag); + profileTierLevel.setLowerBitRateConstraintFlag(m_lowerBitRateConstraintFlag); + + if ((m_profile == Profile::MAIN10) && (g_bitDepth[CHANNEL_TYPE_LUMA] == 8) && (g_bitDepth[CHANNEL_TYPE_CHROMA] == 8)) + { + /* The above constraint is equal to Profile::MAIN */ + profileTierLevel.setProfileCompatibilityFlag(Profile::MAIN, 1); + } + if (m_profile == Profile::MAIN) + { + /* A Profile::MAIN10 decoder can always decode Profile::MAIN */ + profileTierLevel.setProfileCompatibilityFlag(Profile::MAIN10, 1); + } + /* XXX: should Main be marked as compatible with still picture? */ + /* XXX: may be a good idea to refactor the above into a function + * that chooses the actual compatibility based upon options */ + + m_cSPS.setPicWidthInLumaSamples ( m_iSourceWidth ); + m_cSPS.setPicHeightInLumaSamples ( m_iSourceHeight ); + m_cSPS.setConformanceWindow ( m_conformanceWindow ); + m_cSPS.setMaxCUWidth ( g_uiMaxCUWidth ); + m_cSPS.setMaxCUHeight ( g_uiMaxCUHeight ); + m_cSPS.setMaxCUDepth ( g_uiMaxCUDepth ); + m_cSPS.setChromaFormatIdc( m_chromaFormatIDC); + + Int minCUSize = m_cSPS.getMaxCUWidth() >> ( m_cSPS.getMaxCUDepth()-g_uiAddCUDepth ); + Int log2MinCUSize = 0; + while(minCUSize > 1) + { + minCUSize >>= 1; + log2MinCUSize++; + } + + m_cSPS.setLog2MinCodingBlockSize(log2MinCUSize); + m_cSPS.setLog2DiffMaxMinCodingBlockSize(m_cSPS.getMaxCUDepth()-g_uiAddCUDepth-getMaxCUDepthOffset(m_cSPS.getChromaFormatIdc(), m_cSPS.getQuadtreeTULog2MinSize())); + + m_cSPS.setPCMLog2MinSize (m_uiPCMLog2MinSize); + m_cSPS.setUsePCM ( m_usePCM ); + m_cSPS.setPCMLog2MaxSize( m_pcmLog2MaxSize ); + + m_cSPS.setQuadtreeTULog2MaxSize( m_uiQuadtreeTULog2MaxSize ); + m_cSPS.setQuadtreeTULog2MinSize( m_uiQuadtreeTULog2MinSize ); + m_cSPS.setQuadtreeTUMaxDepthInter( m_uiQuadtreeTUMaxDepthInter ); + m_cSPS.setQuadtreeTUMaxDepthIntra( m_uiQuadtreeTUMaxDepthIntra ); + + m_cSPS.setTMVPFlagsPresent(false); + + m_cSPS.setMaxTrSize ( 1 << m_uiQuadtreeTULog2MaxSize ); + + Int i; + + for (i = 0; i < g_uiMaxCUDepth-g_uiAddCUDepth; i++ ) + { + m_cSPS.setAMPAcc( i, m_useAMP ); + //m_cSPS.setAMPAcc( i, 1 ); + } + + m_cSPS.setUseAMP ( m_useAMP ); + + for (i = g_uiMaxCUDepth-g_uiAddCUDepth; i < g_uiMaxCUDepth; i++ ) + { + m_cSPS.setAMPAcc(i, 0); + } + + + for (UInt channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + m_cSPS.setBitDepth (ChannelType(channelType), g_bitDepth[channelType] ); + m_cSPS.setQpBDOffset (ChannelType(channelType), (6 * (g_bitDepth[channelType] - 8))); + m_cSPS.setPCMBitDepth (ChannelType(channelType), g_PCMBitDepth[channelType] ); + } + + m_cSPS.setUseExtendedPrecision(m_useExtendedPrecision); + m_cSPS.setUseHighPrecisionPredictionWeighting(m_useHighPrecisionPredictionWeighting); + + m_cSPS.setUseSAO( m_bUseSAO ); + m_cSPS.setUseResidualRotation(m_useResidualRotation); + m_cSPS.setUseSingleSignificanceMapContext(m_useSingleSignificanceMapContext); + m_cSPS.setUseGolombRiceParameterAdaptation(m_useGolombRiceParameterAdaptation); + m_cSPS.setAlignCABACBeforeBypass(m_alignCABACBeforeBypass); + + for (UInt signallingModeIndex = 0; signallingModeIndex < NUMBER_OF_RDPCM_SIGNALLING_MODES; signallingModeIndex++) + { + m_cSPS.setUseResidualDPCM(RDPCMSignallingMode(signallingModeIndex), m_useResidualDPCM[signallingModeIndex]); + } + + m_cSPS.setMaxTLayers( m_maxTempLayer ); + m_cSPS.setTemporalIdNestingFlag( ( m_maxTempLayer == 1 ) ? true : false ); + + for ( i = 0; i < min(m_cSPS.getMaxTLayers(),(UInt) MAX_TLAYER); i++ ) + { + m_cSPS.setMaxDecPicBuffering(m_maxDecPicBuffering[i], i); + m_cSPS.setNumReorderPics(m_numReorderPics[i], i); + } + + m_cSPS.setPCMFilterDisableFlag ( m_bPCMFilterDisableFlag ); + m_cSPS.setDisableIntraReferenceSmoothing( m_disableIntraReferenceSmoothing ); + m_cSPS.setScalingListFlag ( (m_useScalingListId == 0) ? 0 : 1 ); + m_cSPS.setUseStrongIntraSmoothing( m_useStrongIntraSmoothing ); + m_cSPS.setVuiParametersPresentFlag(getVuiParametersPresentFlag()); + + if (m_cSPS.getVuiParametersPresentFlag()) + { + TComVUI* pcVUI = m_cSPS.getVuiParameters(); + pcVUI->setAspectRatioInfoPresentFlag(getAspectRatioInfoPresentFlag()); + pcVUI->setAspectRatioIdc(getAspectRatioIdc()); + pcVUI->setSarWidth(getSarWidth()); + pcVUI->setSarHeight(getSarHeight()); + pcVUI->setOverscanInfoPresentFlag(getOverscanInfoPresentFlag()); + pcVUI->setOverscanAppropriateFlag(getOverscanAppropriateFlag()); + pcVUI->setVideoSignalTypePresentFlag(getVideoSignalTypePresentFlag()); + pcVUI->setVideoFormat(getVideoFormat()); + pcVUI->setVideoFullRangeFlag(getVideoFullRangeFlag()); + pcVUI->setColourDescriptionPresentFlag(getColourDescriptionPresentFlag()); + pcVUI->setColourPrimaries(getColourPrimaries()); + pcVUI->setTransferCharacteristics(getTransferCharacteristics()); + pcVUI->setMatrixCoefficients(getMatrixCoefficients()); + pcVUI->setChromaLocInfoPresentFlag(getChromaLocInfoPresentFlag()); + pcVUI->setChromaSampleLocTypeTopField(getChromaSampleLocTypeTopField()); + pcVUI->setChromaSampleLocTypeBottomField(getChromaSampleLocTypeBottomField()); + pcVUI->setNeutralChromaIndicationFlag(getNeutralChromaIndicationFlag()); + pcVUI->setDefaultDisplayWindow(getDefaultDisplayWindow()); + pcVUI->setFrameFieldInfoPresentFlag(getFrameFieldInfoPresentFlag()); + pcVUI->setFieldSeqFlag(false); + pcVUI->setHrdParametersPresentFlag(false); + pcVUI->getTimingInfo()->setPocProportionalToTimingFlag(getPocProportionalToTimingFlag()); + pcVUI->getTimingInfo()->setNumTicksPocDiffOneMinus1 (getNumTicksPocDiffOneMinus1() ); + pcVUI->setBitstreamRestrictionFlag(getBitstreamRestrictionFlag()); + pcVUI->setTilesFixedStructureFlag(getTilesFixedStructureFlag()); + pcVUI->setMotionVectorsOverPicBoundariesFlag(getMotionVectorsOverPicBoundariesFlag()); + pcVUI->setMinSpatialSegmentationIdc(getMinSpatialSegmentationIdc()); + pcVUI->setMaxBytesPerPicDenom(getMaxBytesPerPicDenom()); + pcVUI->setMaxBitsPerMinCuDenom(getMaxBitsPerMinCuDenom()); + pcVUI->setLog2MaxMvLengthHorizontal(getLog2MaxMvLengthHorizontal()); + pcVUI->setLog2MaxMvLengthVertical(getLog2MaxMvLengthVertical()); + } +} + +Void TEncTop::xInitPPS() +{ + m_cPPS.setConstrainedIntraPred( m_bUseConstrainedIntraPred ); + Bool bUseDQP = (getMaxCuDQPDepth() > 0)? true : false; + + if((getMaxDeltaQP() != 0 )|| getUseAdaptiveQP()) + { + bUseDQP = true; + } + + if (m_costMode==COST_SEQUENCE_LEVEL_LOSSLESS || m_costMode==COST_LOSSLESS_CODING) bUseDQP=false; + + if(bUseDQP) + { + m_cPPS.setUseDQP(true); + m_cPPS.setMaxCuDQPDepth( m_iMaxCuDQPDepth ); + m_cPPS.setMinCuDQPSize( m_cPPS.getSPS()->getMaxCUWidth() >> ( m_cPPS.getMaxCuDQPDepth()) ); + } + else + { + m_cPPS.setUseDQP(false); + m_cPPS.setMaxCuDQPDepth( 0 ); + m_cPPS.setMinCuDQPSize( m_cPPS.getSPS()->getMaxCUWidth() >> ( m_cPPS.getMaxCuDQPDepth()) ); + } + + if ( m_maxCUChromaQpAdjustmentDepth >= 0 ) + { + m_cPPS.setMaxCuChromaQpAdjDepth(m_maxCUChromaQpAdjustmentDepth); + m_cPPS.setChromaQpAdjTableAt(1, 6, 6); + /* todo, insert table entries from command line (NB, 0 should not be touched) */ + } + else + { + m_cPPS.setMaxCuChromaQpAdjDepth(0); + m_cPPS.clearChromaQpAdjTable(); + } + + if ( m_RCEnableRateControl ) + { + m_cPPS.setUseDQP(true); + m_cPPS.setMaxCuDQPDepth( 0 ); + m_cPPS.setMinCuDQPSize( m_cPPS.getSPS()->getMaxCUWidth() >> ( m_cPPS.getMaxCuDQPDepth()) ); + } + + m_cPPS.setMinCuChromaQpAdjSize( m_cPPS.getSPS()->getMaxCUWidth() >> ( m_cPPS.getMaxCuChromaQpAdjDepth()) ); + + m_cPPS.setQpOffset(COMPONENT_Cb, m_chromaCbQpOffset ); + m_cPPS.setQpOffset(COMPONENT_Cr, m_chromaCrQpOffset ); + + m_cPPS.setNumSubstreams(m_iWaveFrontSubstreams); + m_cPPS.setEntropyCodingSyncEnabledFlag( m_iWaveFrontSynchro > 0 ); + m_cPPS.setTilesEnabledFlag( (m_iNumColumnsMinus1 > 0 || m_iNumRowsMinus1 > 0) ); + m_cPPS.setUseWP( m_useWeightedPred ); + m_cPPS.setWPBiPred( m_useWeightedBiPred ); + m_cPPS.setUseCrossComponentPrediction(m_useCrossComponentPrediction); + m_cPPS.setSaoOffsetBitShift(CHANNEL_TYPE_LUMA, m_saoOffsetBitShift[CHANNEL_TYPE_LUMA ]); + m_cPPS.setSaoOffsetBitShift(CHANNEL_TYPE_CHROMA, m_saoOffsetBitShift[CHANNEL_TYPE_CHROMA]); + m_cPPS.setOutputFlagPresentFlag( false ); + m_cPPS.setSignHideFlag(getSignHideFlag()); + if ( getDeblockingFilterMetric() ) + { + m_cPPS.setDeblockingFilterControlPresentFlag (true); + m_cPPS.setDeblockingFilterOverrideEnabledFlag(true); + m_cPPS.setPicDisableDeblockingFilterFlag(false); + m_cPPS.setDeblockingFilterBetaOffsetDiv2(0); + m_cPPS.setDeblockingFilterTcOffsetDiv2(0); + } + else + { + m_cPPS.setDeblockingFilterControlPresentFlag (m_DeblockingFilterControlPresent ); + } + m_cPPS.setLog2ParallelMergeLevelMinus2 (m_log2ParallelMergeLevelMinus2 ); + m_cPPS.setCabacInitPresentFlag(CABAC_INIT_PRESENT_FLAG); + m_cPPS.setLoopFilterAcrossSlicesEnabledFlag( m_bLFCrossSliceBoundaryFlag ); + + Int histogram[MAX_NUM_REF + 1]; + for( Int i = 0; i <= MAX_NUM_REF; i++ ) + { + histogram[i]=0; + } + for( Int i = 0; i < getGOPSize(); i++) + { + assert(getGOPEntry(i).m_numRefPicsActive >= 0 && getGOPEntry(i).m_numRefPicsActive <= MAX_NUM_REF); + histogram[getGOPEntry(i).m_numRefPicsActive]++; + } + + Int maxHist=-1; + Int bestPos=0; + for( Int i = 0; i <= MAX_NUM_REF; i++ ) + { + if(histogram[i]>maxHist) + { + maxHist=histogram[i]; + bestPos=i; + } + } + assert(bestPos <= 15); + m_cPPS.setNumRefIdxL0DefaultActive(bestPos); + m_cPPS.setNumRefIdxL1DefaultActive(bestPos); + m_cPPS.setTransquantBypassEnableFlag(getTransquantBypassEnableFlag()); + m_cPPS.setUseTransformSkip( m_useTransformSkip ); + m_cPPS.setTransformSkipLog2MaxSize( m_transformSkipLog2MaxSize ); + + if (m_sliceSegmentMode != NO_SLICES) + { + m_cPPS.setDependentSliceSegmentsEnabledFlag( true ); + } +} + +//Function for initializing m_RPSList, a list of TComReferencePictureSet, based on the GOPEntry objects read from the config file. +Void TEncTop::xInitRPS(Bool isFieldCoding) +{ + TComReferencePictureSet* rps; + + m_cSPS.createRPSList(getGOPSize() + m_extraRPSs + 1); + TComRPSList* rpsList = m_cSPS.getRPSList(); + + for( Int i = 0; i < getGOPSize()+m_extraRPSs; i++) + { + GOPEntry ge = getGOPEntry(i); + rps = rpsList->getReferencePictureSet(i); + rps->setNumberOfPictures(ge.m_numRefPics); + rps->setNumRefIdc(ge.m_numRefIdc); + Int numNeg = 0; + Int numPos = 0; + for( Int j = 0; j < ge.m_numRefPics; j++) + { + rps->setDeltaPOC(j,ge.m_referencePics[j]); + rps->setUsed(j,ge.m_usedByCurrPic[j]); + if(ge.m_referencePics[j]>0) + { + numPos++; + } + else + { + numNeg++; + } + } + rps->setNumberOfNegativePictures(numNeg); + rps->setNumberOfPositivePictures(numPos); + + // handle inter RPS intialization from the config file. +#if AUTO_INTER_RPS + rps->setInterRPSPrediction(ge.m_interRPSPrediction > 0); // not very clean, converting anything > 0 to true. + rps->setDeltaRIdxMinus1(0); // index to the Reference RPS is always the previous one. + TComReferencePictureSet* RPSRef = rpsList->getReferencePictureSet(i-1); // get the reference RPS + + if (ge.m_interRPSPrediction == 2) // Automatic generation of the inter RPS idc based on the RIdx provided. + { + Int deltaRPS = getGOPEntry(i-1).m_POC - ge.m_POC; // the ref POC - current POC + Int numRefDeltaPOC = RPSRef->getNumberOfPictures(); + + rps->setDeltaRPS(deltaRPS); // set delta RPS + rps->setNumRefIdc(numRefDeltaPOC+1); // set the numRefIdc to the number of pictures in the reference RPS + 1. + Int count=0; + for (Int j = 0; j <= numRefDeltaPOC; j++ ) // cycle through pics in reference RPS. + { + Int RefDeltaPOC = (jgetDeltaPOC(j): 0; // if it is the last decoded picture, set RefDeltaPOC = 0 + rps->setRefIdc(j, 0); + for (Int k = 0; k < rps->getNumberOfPictures(); k++ ) // cycle through pics in current RPS. + { + if (rps->getDeltaPOC(k) == ( RefDeltaPOC + deltaRPS)) // if the current RPS has a same picture as the reference RPS. + { + rps->setRefIdc(j, (rps->getUsed(k)?1:2)); + count++; + break; + } + } + } + if (count != rps->getNumberOfPictures()) + { + printf("Warning: Unable fully predict all delta POCs using the reference RPS index given in the config file. Setting Inter RPS to false for this RPS.\n"); + rps->setInterRPSPrediction(0); + } + } + else if (ge.m_interRPSPrediction == 1) // inter RPS idc based on the RefIdc values provided in config file. + { + rps->setDeltaRPS(ge.m_deltaRPS); + rps->setNumRefIdc(ge.m_numRefIdc); + for (Int j = 0; j < ge.m_numRefIdc; j++ ) + { + rps->setRefIdc(j, ge.m_refIdc[j]); + } +#if WRITE_BACK + // the folowing code overwrite the deltaPOC and Used by current values read from the config file with the ones + // computed from the RefIdc. A warning is printed if they are not identical. + numNeg = 0; + numPos = 0; + TComReferencePictureSet RPSTemp; // temporary variable + + for (Int j = 0; j < ge.m_numRefIdc; j++ ) + { + if (ge.m_refIdc[j]) + { + Int deltaPOC = ge.m_deltaRPS + ((j < RPSRef->getNumberOfPictures())? RPSRef->getDeltaPOC(j) : 0); + RPSTemp.setDeltaPOC((numNeg+numPos),deltaPOC); + RPSTemp.setUsed((numNeg+numPos),ge.m_refIdc[j]==1?1:0); + if (deltaPOC<0) + { + numNeg++; + } + else + { + numPos++; + } + } + } + if (numNeg != rps->getNumberOfNegativePictures()) + { + printf("Warning: number of negative pictures in RPS is different between intra and inter RPS specified in the config file.\n"); + rps->setNumberOfNegativePictures(numNeg); + rps->setNumberOfPictures(numNeg+numPos); + } + if (numPos != rps->getNumberOfPositivePictures()) + { + printf("Warning: number of positive pictures in RPS is different between intra and inter RPS specified in the config file.\n"); + rps->setNumberOfPositivePictures(numPos); + rps->setNumberOfPictures(numNeg+numPos); + } + RPSTemp.setNumberOfPictures(numNeg+numPos); + RPSTemp.setNumberOfNegativePictures(numNeg); + RPSTemp.sortDeltaPOC(); // sort the created delta POC before comparing + // check if Delta POC and Used are the same + // print warning if they are not. + for (Int j = 0; j < ge.m_numRefIdc; j++ ) + { + if (RPSTemp.getDeltaPOC(j) != rps->getDeltaPOC(j)) + { + printf("Warning: delta POC is different between intra RPS and inter RPS specified in the config file.\n"); + rps->setDeltaPOC(j,RPSTemp.getDeltaPOC(j)); + } + if (RPSTemp.getUsed(j) != rps->getUsed(j)) + { + printf("Warning: Used by Current in RPS is different between intra and inter RPS specified in the config file.\n"); + rps->setUsed(j,RPSTemp.getUsed(j)); + } + } +#endif + } +#else + rps->setInterRPSPrediction(ge.m_interRPSPrediction); + if (ge.m_interRPSPrediction) + { + rps->setDeltaRIdxMinus1(0); + rps->setDeltaRPS(ge.m_deltaRPS); + rps->setNumRefIdc(ge.m_numRefIdc); + for (Int j = 0; j < ge.m_numRefIdc; j++ ) + { + rps->setRefIdc(j, ge.m_refIdc[j]); + } +#if WRITE_BACK + // the folowing code overwrite the deltaPOC and Used by current values read from the config file with the ones + // computed from the RefIdc. This is not necessary if both are identical. Currently there is no check to see if they are identical. + numNeg = 0; + numPos = 0; + TComReferencePictureSet* RPSRef = m_RPSList.getReferencePictureSet(i-1); + + for (Int j = 0; j < ge.m_numRefIdc; j++ ) + { + if (ge.m_refIdc[j]) + { + Int deltaPOC = ge.m_deltaRPS + ((j < RPSRef->getNumberOfPictures())? RPSRef->getDeltaPOC(j) : 0); + rps->setDeltaPOC((numNeg+numPos),deltaPOC); + rps->setUsed((numNeg+numPos),ge.m_refIdc[j]==1?1:0); + if (deltaPOC<0) + { + numNeg++; + } + else + { + numPos++; + } + } + } + rps->setNumberOfNegativePictures(numNeg); + rps->setNumberOfPositivePictures(numPos); + rps->sortDeltaPOC(); +#endif + } +#endif //INTER_RPS_AUTO + } + //In case of field coding, we need to set special parameters for the first bottom field of the sequence, since it is not specified in the cfg file. + //The position = GOPSize + extraRPSs which is (a priori) unused is reserved for this field in the RPS. + if (isFieldCoding) + { + rps = rpsList->getReferencePictureSet(getGOPSize()+m_extraRPSs); + rps->setNumberOfPictures(1); + rps->setNumberOfNegativePictures(1); + rps->setNumberOfPositivePictures(0); + rps->setNumberOfLongtermPictures(0); + rps->setDeltaPOC(0,-1); + rps->setPOC(0,0); + rps->setUsed(0,true); + rps->setInterRPSPrediction(false); + rps->setDeltaRIdxMinus1(0); + rps->setDeltaRPS(0); + rps->setNumRefIdc(0); + } +} + + // This is a function that + // determines what Reference Picture Set to use + // for a specific slice (with POC = POCCurr) +Void TEncTop::selectReferencePictureSet(TComSlice* slice, Int POCCurr, Int GOPid ) +{ + slice->setRPSidx(GOPid); + + for(Int extraNum=m_iGOPSize; extraNum 0 && getDecodingRefreshType() > 0) + { + Int POCIndex = POCCurr%m_uiIntraPeriod; + if(POCIndex == 0) + { + POCIndex = m_uiIntraPeriod; + } + if(POCIndex == m_GOPList[extraNum].m_POC) + { + slice->setRPSidx(extraNum); + } + } + else + { + if(POCCurr==m_GOPList[extraNum].m_POC) + { + slice->setRPSidx(extraNum); + } + } + } + + if(POCCurr == 1 && slice->getPic()->isField()) + { + slice->setRPSidx(m_iGOPSize+m_extraRPSs); + } + + slice->setRPS(getSPS()->getRPSList()->getReferencePictureSet(slice->getRPSidx())); + slice->getRPS()->setNumberOfPictures(slice->getRPS()->getNumberOfNegativePictures()+slice->getRPS()->getNumberOfPositivePictures()); +} + +Int TEncTop::getReferencePictureSetIdxForSOP(TComSlice* slice, Int POCCurr, Int GOPid ) +{ + Int rpsIdx = GOPid; + + for(Int extraNum=m_iGOPSize; extraNum 0 && getDecodingRefreshType() > 0) + { + Int POCIndex = POCCurr%m_uiIntraPeriod; + if(POCIndex == 0) + { + POCIndex = m_uiIntraPeriod; + } + if(POCIndex == m_GOPList[extraNum].m_POC) + { + rpsIdx = extraNum; + } + } + else + { + if(POCCurr==m_GOPList[extraNum].m_POC) + { + rpsIdx = extraNum; + } + } + } + + return rpsIdx; +} + +Void TEncTop::xInitPPSforTiles() +{ + m_cPPS.setTileUniformSpacingFlag( m_tileUniformSpacingFlag ); + m_cPPS.setNumTileColumnsMinus1( m_iNumColumnsMinus1 ); + m_cPPS.setNumTileRowsMinus1( m_iNumRowsMinus1 ); + if( !m_tileUniformSpacingFlag ) + { + m_cPPS.setTileColumnWidth( m_tileColumnWidth ); + m_cPPS.setTileRowHeight( m_tileRowHeight ); + } + m_cPPS.setLoopFilterAcrossTilesEnabledFlag( m_loopFilterAcrossTilesEnabledFlag ); + + // # substreams is "per tile" when tiles are independent. + if (m_iWaveFrontSynchro ) + { + m_cPPS.setNumSubstreams(m_iWaveFrontSubstreams * (m_iNumColumnsMinus1+1)); + } + else + { + m_cPPS.setNumSubstreams((m_iNumRowsMinus1+1) * (m_iNumColumnsMinus1+1)); + } +} + +Void TEncCfg::xCheckGSParameters() +{ + Int iWidthInCU = ( m_iSourceWidth%g_uiMaxCUWidth ) ? m_iSourceWidth/g_uiMaxCUWidth + 1 : m_iSourceWidth/g_uiMaxCUWidth; + Int iHeightInCU = ( m_iSourceHeight%g_uiMaxCUHeight ) ? m_iSourceHeight/g_uiMaxCUHeight + 1 : m_iSourceHeight/g_uiMaxCUHeight; + UInt uiCummulativeColumnWidth = 0; + UInt uiCummulativeRowHeight = 0; + + //check the column relative parameters + if( m_iNumColumnsMinus1 >= (1<<(LOG2_MAX_NUM_COLUMNS_MINUS1+1)) ) + { + printf( "The number of columns is larger than the maximum allowed number of columns.\n" ); + exit( EXIT_FAILURE ); + } + + if( m_iNumColumnsMinus1 >= iWidthInCU ) + { + printf( "The current picture can not have so many columns.\n" ); + exit( EXIT_FAILURE ); + } + + if( m_iNumColumnsMinus1 && !m_tileUniformSpacingFlag ) + { + for(Int i=0; i= iWidthInCU ) + { + printf( "The width of the column is too large.\n" ); + exit( EXIT_FAILURE ); + } + } + + //check the row relative parameters + if( m_iNumRowsMinus1 >= (1<<(LOG2_MAX_NUM_ROWS_MINUS1+1)) ) + { + printf( "The number of rows is larger than the maximum allowed number of rows.\n" ); + exit( EXIT_FAILURE ); + } + + if( m_iNumRowsMinus1 >= iHeightInCU ) + { + printf( "The current picture can not have so many rows.\n" ); + exit( EXIT_FAILURE ); + } + + if( m_iNumRowsMinus1 && !m_tileUniformSpacingFlag ) + { + for(Int i=0; i= iHeightInCU ) + { + printf( "The height of the row is too large.\n" ); + exit( EXIT_FAILURE ); + } + } +} +//! \} diff --git a/jctvc/TLibEncoder/TEncTop.h b/jctvc/TLibEncoder/TEncTop.h new file mode 100644 index 0000000..7ef8bdb --- /dev/null +++ b/jctvc/TLibEncoder/TEncTop.h @@ -0,0 +1,183 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file TEncTop.h + \brief encoder class (header) +*/ + +#ifndef __TENCTOP__ +#define __TENCTOP__ + +// Include files +#include "TLibCommon/TComList.h" +#include "TLibCommon/TComPrediction.h" +#include "TLibCommon/TComTrQuant.h" +#include "TLibCommon/TComLoopFilter.h" +#include "TLibCommon/AccessUnit.h" + +#include "TLibVideoIO/TVideoIOYuv.h" + +#include "TEncCfg.h" +#include "TEncGOP.h" +#include "TEncSlice.h" +#include "TEncEntropy.h" +#include "TEncCavlc.h" +#include "TEncSbac.h" +#include "TEncSearch.h" +#include "TEncSampleAdaptiveOffset.h" +#include "TEncPreanalyzer.h" +#include "TEncRateCtrl.h" +//! \ingroup TLibEncoder +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// encoder class +class TEncTop : public TEncCfg +{ +private: + // picture + Int m_iPOCLast; ///< time index (POC) + Int m_iNumPicRcvd; ///< number of received pictures + UInt m_uiNumAllPicCoded; ///< number of coded pictures + TComList m_cListPic; ///< dynamic list of pictures + + // encoder search + TEncSearch m_cSearch; ///< encoder search class + //TEncEntropy* m_pcEntropyCoder; ///< entropy encoder + TEncCavlc* m_pcCavlcCoder; ///< CAVLC encoder + // coding tool + TComTrQuant m_cTrQuant; ///< transform & quantization class + TComLoopFilter m_cLoopFilter; ///< deblocking filter class + TEncSampleAdaptiveOffset m_cEncSAO; ///< sample adaptive offset class + TEncEntropy m_cEntropyCoder; ///< entropy encoder + TEncCavlc m_cCavlcCoder; ///< CAVLC encoder + TEncSbac m_cSbacCoder; ///< SBAC encoder + TEncBinCABAC m_cBinCoderCABAC; ///< bin coder CABAC + + // processing unit + TEncGOP m_cGOPEncoder; ///< GOP encoder + TEncSlice m_cSliceEncoder; ///< slice encoder + TEncCu m_cCuEncoder; ///< CU encoder + // SPS + TComSPS m_cSPS; ///< SPS + TComPPS m_cPPS; ///< PPS + // RD cost computation + TComRdCost m_cRdCost; ///< RD cost computation class + TEncSbac*** m_pppcRDSbacCoder; ///< temporal storage for RD computation + TEncSbac m_cRDGoOnSbacCoder; ///< going on SBAC model for RD stage +#if FAST_BIT_EST + TEncBinCABACCounter*** m_pppcBinCoderCABAC; ///< temporal CABAC state storage for RD computation + TEncBinCABACCounter m_cRDGoOnBinCoderCABAC; ///< going on bin coder CABAC for RD stage +#else + TEncBinCABAC*** m_pppcBinCoderCABAC; ///< temporal CABAC state storage for RD computation + TEncBinCABAC m_cRDGoOnBinCoderCABAC; ///< going on bin coder CABAC for RD stage +#endif + + // quality control + TEncPreanalyzer m_cPreanalyzer; ///< image characteristics analyzer for TM5-step3-like adaptive QP + + TComScalingList m_scalingList; ///< quantization matrix information + TEncRateCtrl m_cRateCtrl; ///< Rate control class + +protected: + Void xGetNewPicBuffer ( TComPic*& rpcPic ); ///< get picture buffer which will be processed + Void xInitSPS (); ///< initialize SPS from encoder options + Void xInitPPS (); ///< initialize PPS from encoder options + + Void xInitPPSforTiles (); + Void xInitRPS (Bool isFieldCoding); ///< initialize PPS from encoder options + +public: + TEncTop(); + virtual ~TEncTop(); + + Void create (); + Void destroy (); + Void init (Bool isFieldCoding); + Void deletePicBuffer (); + + // ------------------------------------------------------------------------------------------------------------------- + // member access functions + // ------------------------------------------------------------------------------------------------------------------- + + TComList* getListPic () { return &m_cListPic; } + TEncSearch* getPredSearch () { return &m_cSearch; } + + TComTrQuant* getTrQuant () { return &m_cTrQuant; } + TComLoopFilter* getLoopFilter () { return &m_cLoopFilter; } + TEncSampleAdaptiveOffset* getSAO () { return &m_cEncSAO; } + TEncGOP* getGOPEncoder () { return &m_cGOPEncoder; } + TEncSlice* getSliceEncoder () { return &m_cSliceEncoder; } + TEncCu* getCuEncoder () { return &m_cCuEncoder; } + TEncEntropy* getEntropyCoder () { return &m_cEntropyCoder; } + TEncCavlc* getCavlcCoder () { return &m_cCavlcCoder; } + TEncSbac* getSbacCoder () { return &m_cSbacCoder; } + TEncBinCABAC* getBinCABAC () { return &m_cBinCoderCABAC; } + + TComRdCost* getRdCost () { return &m_cRdCost; } + TEncSbac*** getRDSbacCoder () { return m_pppcRDSbacCoder; } + TEncSbac* getRDGoOnSbacCoder () { return &m_cRDGoOnSbacCoder; } + TEncRateCtrl* getRateCtrl () { return &m_cRateCtrl; } + TComSPS* getSPS () { return &m_cSPS; } + TComPPS* getPPS () { return &m_cPPS; } + Void selectReferencePictureSet(TComSlice* slice, Int POCCurr, Int GOPid ); + Int getReferencePictureSetIdxForSOP(TComSlice* slice, Int POCCurr, Int GOPid ); + TComScalingList* getScalingList () { return &m_scalingList; } + // ------------------------------------------------------------------------------------------------------------------- + // encoder function + // ------------------------------------------------------------------------------------------------------------------- + + /// encode several number of pictures until end-of-sequence + Void encode( Bool bEos, + TComPicYuv* pcPicYuvOrg, + TComPicYuv* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, // used for SNR calculations. Picture in original colour space. + TComList& rcListPicYuvRecOut, + std::list& accessUnitsOut, Int& iNumEncoded ); + + /// encode several number of pictures until end-of-sequence + Void encode( Bool bEos, TComPicYuv* pcPicYuvOrg, + TComPicYuv* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, // used for SNR calculations. Picture in original colour space. + TComList& rcListPicYuvRecOut, + std::list& accessUnitsOut, Int& iNumEncoded, Bool isTff); + + Void printSummary(Bool isField) { m_cGOPEncoder.printOutSummary (m_uiNumAllPicCoded, isField, m_printMSEBasedSequencePSNR, m_printSequenceMSE); } + +}; + +//! \} + +#endif // __TENCTOP__ + diff --git a/jctvc/TLibEncoder/WeightPredAnalysis.cpp b/jctvc/TLibEncoder/WeightPredAnalysis.cpp new file mode 100644 index 0000000..aa285c8 --- /dev/null +++ b/jctvc/TLibEncoder/WeightPredAnalysis.cpp @@ -0,0 +1,386 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file WeightPredAnalysis.cpp + \brief weighted prediction encoder class +*/ + +#include "../TLibCommon/TypeDef.h" +#include "../TLibCommon/TComSlice.h" +#include "../TLibCommon/TComPic.h" +#include "../TLibCommon/TComPicYuv.h" +#include "WeightPredAnalysis.h" + +#define ABS(a) ((a) < 0 ? - (a) : (a)) +#define DTHRESH (0.99) + +WeightPredAnalysis::WeightPredAnalysis() +{ + m_weighted_pred_flag = false; + m_weighted_bipred_flag = false; + + for ( UInt lst =0 ; lstbPresentFlag = false; + pwp->uiLog2WeightDenom = 0; + pwp->iWeight = 1; + pwp->iOffset = 0; + } + } + } +} + + +/** calculate AC and DC values for current original image + * \param TComSlice *slice + * \returns Void + */ +Void WeightPredAnalysis::xCalcACDCParamSlice(TComSlice *const slice) +{ + //===== calculate AC/DC value ===== + TComPicYuv* pPic = slice->getPic()->getPicYuvOrg(); + + WPACDCParam weightACDCParam[MAX_NUM_COMPONENT]; + + for(Int componentIndex = 0; componentIndex < pPic->getNumberValidComponents(); componentIndex++) + { + const ComponentID compID = ComponentID(componentIndex); + + // calculate DC/AC value for channel + + const Int iStride = pPic->getStride(compID); + const Int iWidth = pPic->getWidth(compID); + const Int iHeight = pPic->getHeight(compID); + + const Int iSample = iWidth*iHeight; + + Int64 iOrgDC = 0; + { + const Pel *pPel = pPic->getAddr(compID); + + for(Int y = 0; y < iHeight; y++, pPel+=iStride ) + for(Int x = 0; x < iWidth; x++ ) + iOrgDC += (Int)( pPel[x] ); + } + + const Int64 iOrgNormDC = ((iOrgDC+(iSample>>1)) / iSample); + + Int64 iOrgAC = 0; + { + const Pel *pPel = pPic->getAddr(compID); + + for(Int y = 0; y < iHeight; y++, pPel += iStride ) + for(Int x = 0; x < iWidth; x++ ) + iOrgAC += abs( (Int)pPel[x] - (Int)iOrgNormDC ); + } + + const Int fixedBitShift = (slice->getSPS()->getUseHighPrecisionPredictionWeighting())?RExt__PREDICTION_WEIGHTING_ANALYSIS_DC_PRECISION:0; + weightACDCParam[compID].iDC = (((iOrgDC<>1)) / iSample); + weightACDCParam[compID].iAC = iOrgAC; + } + + slice->setWpAcDcParam(weightACDCParam); +} + + +/** store weighted_pred_flag and weighted_bipred_idc values + * \param weighted_pred_flag + * \param weighted_bipred_idc + * \returns Void + */ +Void WeightPredAnalysis::xStoreWPparam(const Bool weighted_pred_flag, const Bool weighted_bipred_flag) +{ + m_weighted_pred_flag = weighted_pred_flag; + m_weighted_bipred_flag = weighted_bipred_flag; +} + + +/** restore weighted_pred_flag and weighted_bipred_idc values + * \param TComSlice *slice + * \returns Void + */ +Void WeightPredAnalysis::xRestoreWPparam(TComSlice *const slice) +{ + slice->getPPS()->setUseWP (m_weighted_pred_flag); + slice->getPPS()->setWPBiPred(m_weighted_bipred_flag); +} + + +/** check weighted pred or non-weighted pred + * \param TComSlice *slice + * \returns Void + */ +Void WeightPredAnalysis::xCheckWPEnable(TComSlice *const slice) +{ + const TComPicYuv *pPic = slice->getPic()->getPicYuvOrg(); + + Int iPresentCnt = 0; + for ( UInt lst=0 ; lstgetNumberValidComponents(); componentIndex++) + { + WPScalingParam *pwp = &(m_wp[lst][iRefIdx][componentIndex]); + iPresentCnt += (Int)pwp->bPresentFlag; + } + } + } + + if(iPresentCnt==0) + { + slice->getPPS()->setUseWP(false); + slice->getPPS()->setWPBiPred(false); + + for ( UInt lst=0 ; lstgetNumberValidComponents(); componentIndex++) + { + WPScalingParam *pwp = &(m_wp[lst][iRefIdx][componentIndex]); + + pwp->bPresentFlag = false; + pwp->uiLog2WeightDenom = 0; + pwp->iWeight = 1; + pwp->iOffset = 0; + } + } + } + slice->setWpScaling( m_wp ); + } +} + + +/** estimate wp tables for explicit wp + * \param TComSlice *slice + */ +Void WeightPredAnalysis::xEstimateWPParamSlice(TComSlice *const slice) +{ + Int iDenom = 6; + Bool validRangeFlag = false; + + if(slice->getNumRefIdx(REF_PIC_LIST_0)>3) + { + iDenom = 7; + } + + do + { + validRangeFlag = xUpdatingWPParameters(slice, iDenom); + if (!validRangeFlag) + { + iDenom--; // decrement to satisfy the range limitation + } + } while (validRangeFlag == false); + + // selecting whether WP is used, or not + xSelectWP(slice, iDenom); + + slice->setWpScaling( m_wp ); +} + + +/** update wp tables for explicit wp w.r.t ramge limitation + * \param TComSlice *slice + * \returns Bool + */ +Bool WeightPredAnalysis::xUpdatingWPParameters(TComSlice *const slice, const Int log2Denom) +{ + const Int numComp = slice->getPic()->getPicYuvOrg()->getNumberValidComponents(); + const Bool bUseHighPrecisionWeighting = slice->getSPS()->getUseHighPrecisionPredictionWeighting(); + const Int numPredDir = slice->isInterP() ? 1 : 2; + + assert (numPredDir <= Int(NUM_REF_PIC_LIST_01)); + + for ( Int refList = 0; refList < numPredDir; refList++ ) + { + const RefPicList eRefPicList = ( refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); + + for ( Int refIdxTemp = 0; refIdxTemp < slice->getNumRefIdx(eRefPicList); refIdxTemp++ ) + { + WPACDCParam *currWeightACDCParam, *refWeightACDCParam; + slice->getWpAcDcParam(currWeightACDCParam); + slice->getRefPic(eRefPicList, refIdxTemp)->getSlice(0)->getWpAcDcParam(refWeightACDCParam); + + for ( Int comp = 0; comp < numComp; comp++ ) + { + const ComponentID compID = ComponentID(comp); + const Int range = bUseHighPrecisionWeighting ? (1<> realLog2Denom ); + + Int clippedOffset; + if(isChroma(compID)) // Chroma offset range limination + { + const Int pred = ( range - ( ( range*weight)>>(log2Denom) ) ); + const Int deltaOffset = Clip3( -4*range, 4*range-1, (offset - pred) ); // signed 10bit + + clippedOffset = Clip3( -range, range-1, (deltaOffset + pred) ); // signed 8bit + } + else // Luma offset range limitation + { + clippedOffset = Clip3( -range, range-1, offset); + } + + // Weighting factor limitation + const Int defaultWeight = (1<= range || deltaWeight < -range) + return false; + + m_wp[refList][refIdxTemp][comp].bPresentFlag = true; + m_wp[refList][refIdxTemp][comp].iWeight = weight; + m_wp[refList][refIdxTemp][comp].iOffset = clippedOffset; + m_wp[refList][refIdxTemp][comp].uiLog2WeightDenom = log2Denom; + } + } + } + return true; +} + + +/** select whether weighted pred enables or not. + * \param TComSlice *slice + * \param log2Denom + * \returns Bool + */ +Bool WeightPredAnalysis::xSelectWP(TComSlice *const slice, const Int log2Denom) +{ + TComPicYuv *const pPic = slice->getPic()->getPicYuvOrg(); + const Int iDefaultWeight = ((Int)1<isInterP() ? 1 : 2; + const Bool useHighPrecisionPredictionWeighting = slice->getSPS()->getUseHighPrecisionPredictionWeighting(); + + assert (iNumPredDir <= Int(NUM_REF_PIC_LIST_01)); + + for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) + { + const RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); + + for ( Int iRefIdxTemp = 0; iRefIdxTemp < slice->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) + { + Int64 iSADWP = 0, iSADnoWP = 0; + + for(Int comp=0; compgetNumberValidComponents(); comp++) + { + const ComponentID compID = ComponentID(comp); + Pel *pOrg = pPic->getAddr(compID); + Pel *pRef = slice->getRefPic(eRefPicList, iRefIdxTemp)->getPicYuvRec()->getAddr(compID); + const Int iOrgStride = pPic->getStride(compID); + const Int iRefStride = slice->getRefPic(eRefPicList, iRefIdxTemp)->getPicYuvRec()->getStride(compID); + const Int iWidth = pPic->getWidth(compID); + const Int iHeight = pPic->getHeight(compID); + const Int bitDepth = g_bitDepth[toChannelType(compID)]; + + // calculate SAD costs with/without wp for luma + iSADWP += xCalcSADvalueWP(bitDepth, pOrg, pRef, iWidth, iHeight, iOrgStride, iRefStride, log2Denom, m_wp[iRefList][iRefIdxTemp][compID].iWeight, m_wp[iRefList][iRefIdxTemp][compID].iOffset, useHighPrecisionPredictionWeighting); + iSADnoWP += xCalcSADvalueWP(bitDepth, pOrg, pRef, iWidth, iHeight, iOrgStride, iRefStride, log2Denom, iDefaultWeight, 0, useHighPrecisionPredictionWeighting); + } + + const Double dRatio = ((Double)iSADWP / (Double)iSADnoWP); + if(dRatio >= (Double)DTHRESH) + { + for(Int comp=0; compgetNumberValidComponents(); comp++) + { + m_wp[iRefList][iRefIdxTemp][comp].bPresentFlag = false; + m_wp[iRefList][iRefIdxTemp][comp].iOffset = 0; + m_wp[iRefList][iRefIdxTemp][comp].iWeight = iDefaultWeight; + m_wp[iRefList][iRefIdxTemp][comp].uiLog2WeightDenom = log2Denom; + } + } + } + } + + return true; +} + + +/** calculate SAD values for both WP version and non-WP version. + * \param Pel *pOrgPel + * \param Pel *pRefPel + * \param Int iWidth + * \param Int iHeight + * \param Int iOrgStride + * \param Int iRefStride + * \param Int iLog2Denom + * \param Int iWeight + * \param Int iOffset + * \returns Int64 + */ +Int64 WeightPredAnalysis::xCalcSADvalueWP(const Int bitDepth, + const Pel *pOrgPel, + const Pel *pRefPel, + const Int iWidth, + const Int iHeight, + const Int iOrgStride, + const Int iRefStride, + const Int iLog2Denom, + const Int iWeight, + const Int iOffset, + const Bool useHighPrecisionPredictionWeighting) +{ + const Int64 iSize = iWidth*iHeight; + const Int64 iRealLog2Denom = useHighPrecisionPredictionWeighting ? iLog2Denom : (iLog2Denom + (bitDepth - 8)); + + Int64 iSAD = 0; + for( Int y = 0; y < iHeight; y++ ) + { + for( Int x = 0; x < iWidth; x++ ) + { + iSAD += ABS(( ((Int64)pOrgPel[x]<<(Int64)iLog2Denom) - ( (Int64)pRefPel[x] * (Int64)iWeight + ((Int64)iOffset< +#include +#include +#include +#include +#include +#include + +#include "TLibCommon/TComRom.h" +#include "TVideoIOYuv.h" + +using namespace std; + +// ==================================================================================================================== +// Local Functions +// ==================================================================================================================== + +/** + * Scale all pixels in img depending upon sign of shiftbits by a factor of + * 2shiftbits. + * + * @param img pointer to image to be transformed + * @param stride distance between vertically adjacent pixels of img. + * @param width width of active area in img. + * @param height height of active area in img. + * @param shiftbits if zero, no operation performed + * if > 0, multiply by 2shiftbits, see scalePlane() + * if < 0, divide and round by 2shiftbits and clip, + * see invScalePlane(). + * @param minval minimum clipping value when dividing. + * @param maxval maximum clipping value when dividing. + */ +static Void scalePlane(Pel* img, const UInt stride, const UInt width, const UInt height, Int shiftbits, Pel minval, Pel maxval) +{ + if (shiftbits > 0) + { + for (UInt y = 0; y < height; y++, img+=stride) + for (UInt x = 0; x < width; x++) + img[x] <<= shiftbits; + } + else if (shiftbits < 0) + { + shiftbits=-shiftbits; + + Pel rounding = 1 << (shiftbits-1); + for (UInt y = 0; y < height; y++, img+=stride) + for (UInt x = 0; x < width; x++) + img[x] = Clip3(minval, maxval, Pel((img[x] + rounding) >> shiftbits)); + } +} + + +// ==================================================================================================================== +// Public member functions +// ==================================================================================================================== + +/** + * Open file for reading/writing Y'CbCr frames. + * + * Frames read/written have bitdepth fileBitDepth, and are automatically + * formatted as 8 or 16 bit word values (see TVideoIOYuv::write()). + * + * Image data read or written is converted to/from internalBitDepth + * (See scalePlane(), TVideoIOYuv::read() and TVideoIOYuv::write() for + * further details). + * + * \param pchFile file name string + * \param bWriteMode file open mode: true=read, false=write + * \param fileBitDepth bit-depth array of input/output file data. + * \param internalBitDepth bit-depth array to scale image data to/from when reading/writing. + */ +Void TVideoIOYuv::open( Char* pchFile, Bool bWriteMode, const Int fileBitDepth[MAX_NUM_CHANNEL_TYPE], const Int MSBExtendedBitDepth[MAX_NUM_CHANNEL_TYPE], const Int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ) +{ + //NOTE: files cannot have bit depth greater than 16 + for(UInt ch=0; ch(fileBitDepth[ch], 16); + m_MSBExtendedBitDepth[ch] = MSBExtendedBitDepth[ch]; + m_bitdepthShift [ch] = internalBitDepth[ch] - m_MSBExtendedBitDepth[ch]; + + if (m_fileBitdepth[ch] > 16) + { + if (bWriteMode) + { + std::cerr << "\nWARNING: Cannot write a yuv file of bit depth greater than 16 - output will be right-shifted down to 16-bit precision\n" << std::endl; + } + else + { + std::cerr << "\nERROR: Cannot read a yuv file of bit depth greater than 16\n" << std::endl; + exit(0); + } + } + } + + if ( bWriteMode ) + { + m_cHandle.open( pchFile, ios::binary | ios::out ); + + if( m_cHandle.fail() ) + { + printf("\nfailed to write reconstructed YUV file\n"); + exit(0); + } + } + else + { + m_cHandle.open( pchFile, ios::binary | ios::in ); + + if( m_cHandle.fail() ) + { + printf("\nfailed to open Input YUV file\n"); + exit(0); + } + } + + return; +} + +Void TVideoIOYuv::close() +{ + m_cHandle.close(); +} + +Bool TVideoIOYuv::isEof() +{ + return m_cHandle.eof(); +} + +Bool TVideoIOYuv::isFail() +{ + return m_cHandle.fail(); +} + +/** + * Skip numFrames in input. + * + * This function correctly handles cases where the input file is not + * seekable, by consuming bytes. + */ +Void TVideoIOYuv::skipFrames(UInt numFrames, UInt width, UInt height, ChromaFormat format) +{ + if (!numFrames) + return; + + //------------------ + //set the frame size according to the chroma format + streamoff frameSize = 0; + UInt wordsize=1; // default to 8-bit, unless a channel with more than 8-bits is detected. + for (UInt component = 0; component < getNumberValidComponents(format); component++) + { + ComponentID compID=ComponentID(component); + frameSize += (width >> getComponentScaleX(compID, format)) * (height >> getComponentScaleY(compID, format)); + if (m_fileBitdepth[toChannelType(compID)] > 8) wordsize=2; + } + frameSize *= wordsize; + //------------------ + + const streamoff offset = frameSize * numFrames; + + /* attempt to seek */ + if (!!m_cHandle.seekg(offset, ios::cur)) + return; /* success */ + m_cHandle.clear(); + + /* fall back to consuming the input */ + Char buf[512]; + const UInt offset_mod_bufsize = offset % sizeof(buf); + for (streamoff i = 0; i < offset - offset_mod_bufsize; i += sizeof(buf)) + { + m_cHandle.read(buf, sizeof(buf)); + } + m_cHandle.read(buf, offset_mod_bufsize); +} + +/** + * Read width*height pixels from fd into dst, optionally + * padding the left and right edges by edge-extension. Input may be + * either 8bit or 16bit little-endian lsb-aligned words. + * + * @param dst destination image + * @param fd input file stream + * @param is16bit true if input file carries > 8bit data, false otherwise. + * @param stride distance between vertically adjacent pixels of dst. + * @param width width of active area in dst. + * @param height height of active area in dst. + * @param pad_x length of horizontal padding. + * @param pad_y length of vertical padding. + * @return true for success, false in case of error + */ +static Bool readPlane(Pel* dst, + istream& fd, + Bool is16bit, + UInt stride444, + UInt width444, + UInt height444, + UInt pad_x444, + UInt pad_y444, + const ComponentID compID, + const ChromaFormat destFormat, + const ChromaFormat fileFormat, + const UInt fileBitDepth) +{ + const UInt csx_file =getComponentScaleX(compID, fileFormat); + const UInt csy_file =getComponentScaleY(compID, fileFormat); + const UInt csx_dest =getComponentScaleX(compID, destFormat); + const UInt csy_dest =getComponentScaleY(compID, destFormat); + + const UInt width_dest = width444 >>csx_dest; + const UInt height_dest = height444>>csy_dest; + const UInt pad_x_dest = pad_x444>>csx_dest; + const UInt pad_y_dest = pad_y444>>csy_dest; + const UInt stride_dest = stride444>>csx_dest; + + const UInt full_width_dest = width_dest+pad_x_dest; + const UInt full_height_dest = height_dest+pad_y_dest; + + const UInt stride_file = (width444 * (is16bit ? 2 : 1)) >> csx_file; + + UChar *buf = new UChar[stride_file]; + + if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || destFormat==CHROMA_400)) + { + if (destFormat!=CHROMA_400) + { + // set chrominance data to mid-range: (1<<(fileBitDepth-1)) + const Pel value=Pel(1<<(fileBitDepth-1)); + for (UInt y = 0; y < full_height_dest; y++, dst+=stride_dest) + for (UInt x = 0; x < full_width_dest; x++) + dst[x] = value; + } + + if (fileFormat!=CHROMA_400) + { + const UInt height_file = height444>>csy_file; + fd.seekg(height_file*stride_file, ios::cur); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + } + else + { + const UInt mask_y_file=(1<(buf), stride_file); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + + if ((y444&mask_y_dest)==0) + { + // process current destination line + if (csx_file < csx_dest) + { + // eg file is 444, dest is 422. + const UInt sx=csx_dest-csx_file; + if (!is16bit) + { + for (UInt x = 0; x < width_dest; x++) + dst[x] = buf[x<>sx]; + } + else + { + for (UInt x = 0; x < width_dest; x++) + dst[x] = Pel(buf[(x>>sx)*2+0]) | (Pel(buf[(x>>sx)*2+1])<<8); + } + } + + // process right hand side padding + const Pel val=dst[width_dest-1]; + for (UInt x = width_dest; x < full_width_dest; x++) + dst[x] = val; + + dst += stride_dest; + } + } + + // process lower padding + for (UInt y = height_dest; y < full_height_dest; y++, dst+=stride_dest) + for (UInt x = 0; x < full_width_dest; x++) + dst[x] = (dst - stride_dest)[x]; + } + delete[] buf; + return true; +} + +/** + * Write width*height pixels info fd from src. + * + * @param fd output file stream + * @param src source image + * @param is16bit true if input file carries > 8bit data, false otherwise. + * @param stride distance between vertically adjacent pixels of src. + * @param width width of active area in src. + * @param height height of active area in src. + * @return true for success, false in case of error + */ +static Bool writePlane(ostream& fd, Pel* src, Bool is16bit, + UInt stride444, + UInt width444, UInt height444, + const ComponentID compID, + const ChromaFormat srcFormat, + const ChromaFormat fileFormat, + const UInt fileBitDepth) +{ + const UInt csx_file =getComponentScaleX(compID, fileFormat); + const UInt csy_file =getComponentScaleY(compID, fileFormat); + const UInt csx_src =getComponentScaleX(compID, srcFormat); + const UInt csy_src =getComponentScaleY(compID, srcFormat); + + const UInt stride_src = stride444>>csx_src; + + const UInt stride_file = (width444 * (is16bit ? 2 : 1)) >> csx_file; + const UInt width_file = width444 >>csx_file; + const UInt height_file = height444>>csy_file; + + UChar *buf = new UChar[stride_file]; + + if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400)) + { + if (fileFormat!=CHROMA_400) + { + const UInt value=1<<(fileBitDepth-1); + + for(UInt y=0; y< height_file; y++) + { + if (!is16bit) + { + UChar val(value); + for (UInt x = 0; x < width_file; x++) + buf[x]=val; + } + else + { + UShort val(value); + for (UInt x = 0; x < width_file; x++) + { + buf[2*x+0]= (val>>0) & 0xff; + buf[2*x+1]= (val>>8) & 0xff; + } + } + + fd.write(reinterpret_cast(buf), stride_file); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + } + } + else + { + const UInt mask_y_file=(1<>sx]); + } + } + else + { + for (UInt x = 0; x < width_file; x++) + { + buf[2*x ] = (src[x>>sx]>>0) & 0xff; + buf[2*x+1] = (src[x>>sx]>>8) & 0xff; + } + } + } + else + { + // eg file is 422, src is 444. + const UInt sx=csx_file-csx_src; + if (!is16bit) + { + for (UInt x = 0; x < width_file; x++) + { + buf[x] = (UChar)(src[x<>0) & 0xff; + buf[2*x+1] = (src[x<>8) & 0xff; + } + } + } + + fd.write(reinterpret_cast(buf), stride_file); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + + if ((y444&mask_y_src)==0) + { + src += stride_src; + } + + } + } + delete[] buf; + return true; +} + +static Bool writeField(ostream& fd, Pel* top, Pel* bottom, Bool is16bit, + UInt stride444, + UInt width444, UInt height444, + const ComponentID compID, + const ChromaFormat srcFormat, + const ChromaFormat fileFormat, + const UInt fileBitDepth, const Bool isTff) +{ + const UInt csx_file =getComponentScaleX(compID, fileFormat); + const UInt csy_file =getComponentScaleY(compID, fileFormat); + const UInt csx_src =getComponentScaleX(compID, srcFormat); + const UInt csy_src =getComponentScaleY(compID, srcFormat); + + const UInt stride_src = stride444>>csx_src; + + const UInt stride_file = (width444 * (is16bit ? 2 : 1)) >> csx_file; + const UInt width_file = width444 >>csx_file; + const UInt height_file = height444>>csy_file; + + UChar *buf = new UChar[stride_file * 2]; + + if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400)) + { + if (fileFormat!=CHROMA_400) + { + const UInt value=1<<(fileBitDepth-1); + + for(UInt y=0; y< height_file; y++) + { + for (UInt field = 0; field < 2; field++) + { + UChar *fieldBuffer = buf + (field * stride_file); + + if (!is16bit) + { + UChar val(value); + for (UInt x = 0; x < width_file; x++) + fieldBuffer[x]=val; + } + else + { + UShort val(value); + for (UInt x = 0; x < width_file; x++) + { + fieldBuffer[2*x+0]= (val>>0) & 0xff; + fieldBuffer[2*x+1]= (val>>8) & 0xff; + } + } + } + + fd.write(reinterpret_cast(buf), (stride_file * 2)); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + } + } + else + { + const UInt mask_y_file=(1<>sx]); + } + } + else + { + for (UInt x = 0; x < width_file; x++) + { + fieldBuffer[2*x ] = (src[x>>sx]>>0) & 0xff; + fieldBuffer[2*x+1] = (src[x>>sx]>>8) & 0xff; + } + } + } + else + { + // eg file is 422, src is 444. + const UInt sx=csx_file-csx_src; + if (!is16bit) + { + for (UInt x = 0; x < width_file; x++) + { + fieldBuffer[x] = (UChar)(src[x<>0) & 0xff; + fieldBuffer[2*x+1] = (src[x<>8) & 0xff; + } + } + } + } + + fd.write(reinterpret_cast(buf), (stride_file * 2)); + if (fd.eof() || fd.fail() ) + { + delete[] buf; + return false; + } + } + + if ((y444&mask_y_src)==0) + { + top += stride_src; + bottom += stride_src; + } + + } + } + delete[] buf; + return true; +} + +/** + * Read one Y'CbCr frame, performing any required input scaling to change + * from the bitdepth of the input file to the internal bit-depth. + * + * If a bit-depth reduction is required, and internalBitdepth >= 8, then + * the input file is assumed to be ITU-R BT.601/709 compliant, and the + * resulting data is clipped to the appropriate legal range, as if the + * file had been provided at the lower-bitdepth compliant to Rec601/709. + * + * @param pPicYuv input picture YUV buffer class pointer + * @param aiPad source padding size, aiPad[0] = horizontal, aiPad[1] = vertical + * @return true for success, false in case of error + */ +Bool TVideoIOYuv::read ( TComPicYuv* pPicYuvUser, TComPicYuv* pPicYuvTrueOrg, const InputColourSpaceConversion ipcsc, Int aiPad[2], ChromaFormat format ) +{ + // check end-of-file + if ( isEof() ) return false; + TComPicYuv *pPicYuv=pPicYuvTrueOrg; + if (format>=NUM_CHROMA_FORMAT) format=pPicYuv->getChromaFormat(); + + Bool is16bit = false; + + for(UInt ch=0; ch 8) is16bit=true; + } + + const UInt stride444 = pPicYuv->getStride(COMPONENT_Y); + + // compute actual YUV width & height excluding padding size + const UInt pad_h444 = aiPad[0]; + const UInt pad_v444 = aiPad[1]; + + const UInt width_full444 = pPicYuv->getWidth(COMPONENT_Y); + const UInt height_full444 = pPicYuv->getHeight(COMPONENT_Y); + + const UInt width444 = width_full444 - pad_h444; + const UInt height444 = height_full444 - pad_v444; + + for(UInt comp=0; comp= 8); /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */ + const Pel minval = b709Compliance? (( 1 << (desired_bitdepth - 8)) ) : 0; + const Pel maxval = b709Compliance? ((0xff << (desired_bitdepth - 8)) -1) : (1 << desired_bitdepth) - 1; +#endif + + if (! readPlane(pPicYuv->getAddr(compID), m_cHandle, is16bit, stride444, width444, height444, pad_h444, pad_v444, compID, pPicYuv->getChromaFormat(), format, m_fileBitdepth[chType])) + { + return false; + } + + if (compID < pPicYuv->getNumberValidComponents() ) + { + const UInt csx=getComponentScaleX(compID, pPicYuv->getChromaFormat()); + const UInt csy=getComponentScaleY(compID, pPicYuv->getChromaFormat()); + scalePlane(pPicYuv->getAddr(compID), stride444>>csx, width_full444>>csx, height_full444>>csy, m_bitdepthShift[chType], minval, maxval); + } + } + + Int internalBitDepth[MAX_NUM_CHANNEL_TYPE]; + for(UInt chType=0; chTypegetWidth(COMPONENT_Y), pPicYuvUser->getHeight(COMPONENT_Y), pPicYuvUser->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); + Int internalBitDepth[MAX_NUM_CHANNEL_TYPE]; + for(UInt chType=0; chTypegetStride(COMPONENT_Y); + const UInt width444 = pPicYuv->getWidth(COMPONENT_Y) - confLeft - confRight; + const UInt height444 = pPicYuv->getHeight(COMPONENT_Y) - confTop - confBottom; + Bool is16bit = false; + Bool nonZeroBitDepthShift=false; + + if ((width444 == 0) || (height444 == 0)) + { + printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444); + } + + for(UInt ch=0; ch 8) is16bit=true; + if (m_bitdepthShift[ch] != 0) nonZeroBitDepthShift=true; + } + + TComPicYuv *dstPicYuv = NULL; + Bool retval = true; + if (format>=NUM_CHROMA_FORMAT) format=pPicYuv->getChromaFormat(); + + if (nonZeroBitDepthShift) + { + dstPicYuv = new TComPicYuv; + dstPicYuv->create( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat(), 1, 1, 0 ); + pPicYuv->copyToPic(dstPicYuv); + + for(UInt comp=0; compgetNumberValidComponents(); comp++) + { + const ComponentID compID=ComponentID(comp); + const ChannelType ch=toChannelType(compID); +#if !CLIP_TO_709_RANGE + const Pel minval = 0; + const Pel maxval = (1 << m_MSBExtendedBitDepth[ch]) - 1; +#else + const Bool b709Compliance=(-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8); /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */ + const Pel minval = b709Compliance? (( 1 << (m_MSBExtendedBitDepth[ch] - 8)) ) : 0; + const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1; +#endif + + scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval); + } + } + else + { + dstPicYuv = pPicYuv; + } + + for(UInt comp=0; retval && compgetNumberValidComponents(); comp++) + { + const ComponentID compID = ComponentID(comp); + const ChannelType ch=toChannelType(compID); + const UInt csx = pPicYuv->getComponentScaleX(compID); + const UInt csy = pPicYuv->getComponentScaleY(compID); + const Int planeOffset = (confLeft>>csx) + (confTop>>csy) * pPicYuv->getStride(compID); + if (! writePlane(m_cHandle, dstPicYuv->getAddr(compID) + planeOffset, is16bit, iStride444, width444, height444, compID, dstPicYuv->getChromaFormat(), format, m_fileBitdepth[ch])) + { + retval=false; + } + } + + if (nonZeroBitDepthShift) + { + dstPicYuv->destroy(); + delete dstPicYuv; + } + + cPicYuvCSCd.destroy(); + + return retval; +} + +Bool TVideoIOYuv::write( TComPicYuv* pPicYuvUserTop, TComPicYuv* pPicYuvUserBottom, const InputColourSpaceConversion ipCSC, Int confLeft, Int confRight, Int confTop, Int confBottom, ChromaFormat format, const Bool isTff ) +{ + + TComPicYuv cPicYuvTopCSCd; + TComPicYuv cPicYuvBottomCSCd; + if (ipCSC!=IPCOLOURSPACE_UNCHANGED) + { + cPicYuvTopCSCd .create(pPicYuvUserTop ->getWidth(COMPONENT_Y), pPicYuvUserTop ->getHeight(COMPONENT_Y), pPicYuvUserTop ->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); + cPicYuvBottomCSCd.create(pPicYuvUserBottom->getWidth(COMPONENT_Y), pPicYuvUserBottom->getHeight(COMPONENT_Y), pPicYuvUserBottom->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); + Int internalBitDepth[MAX_NUM_CHANNEL_TYPE]; + for(UInt chType=0; chType 8) is16bit=true; + if (m_bitdepthShift[ch] != 0) nonZeroBitDepthShift=true; + } + + TComPicYuv *dstPicYuvTop = NULL; + TComPicYuv *dstPicYuvBottom = NULL; + + for (UInt field = 0; field < 2; field++) + { + TComPicYuv *pPicYuv = (field == 0) ? pPicYuvTop : pPicYuvBottom; + + if (format>=NUM_CHROMA_FORMAT) format=pPicYuv->getChromaFormat(); + + TComPicYuv* &dstPicYuv = (field == 0) ? dstPicYuvTop : dstPicYuvBottom; + + if (nonZeroBitDepthShift) + { + dstPicYuv = new TComPicYuv; + dstPicYuv->create( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat(), 1, 1, 0 ); + pPicYuv->copyToPic(dstPicYuv); + + for(UInt comp=0; compgetNumberValidComponents(); comp++) + { + const ComponentID compID=ComponentID(comp); + const ChannelType ch=toChannelType(compID); +#if !CLIP_TO_709_RANGE + const Pel minval = 0; + const Pel maxval = (1 << m_MSBExtendedBitDepth[ch]) - 1; +#else + const Bool b709Compliance=(-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8); /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */ + const Pel minval = b709Compliance? (( 1 << (m_MSBExtendedBitDepth[ch] - 8)) ) : 0; + const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1; +#endif + + scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval); + } + } + else + { + dstPicYuv = pPicYuv; + } + } + + Bool retval = true; + + assert(dstPicYuvTop->getNumberValidComponents() == dstPicYuvBottom->getNumberValidComponents()); + assert(dstPicYuvTop->getChromaFormat() == dstPicYuvBottom->getChromaFormat() ); + assert(dstPicYuvTop->getWidth(COMPONENT_Y) == dstPicYuvBottom->getWidth(COMPONENT_Y) ); + assert(dstPicYuvTop->getHeight(COMPONENT_Y) == dstPicYuvBottom->getHeight(COMPONENT_Y) ); + assert(dstPicYuvTop->getStride(COMPONENT_Y) == dstPicYuvBottom->getStride(COMPONENT_Y) ); + + for(UInt comp=0; retval && compgetNumberValidComponents(); comp++) + { + const ComponentID compID = ComponentID(comp); + const ChannelType ch=toChannelType(compID); + + assert(dstPicYuvTop->getComponentScaleX(compID) == dstPicYuvBottom->getComponentScaleX(compID)); + assert(dstPicYuvTop->getComponentScaleY(compID) == dstPicYuvBottom->getComponentScaleY(compID)); + assert(dstPicYuvTop->getStride (compID) == dstPicYuvBottom->getStride (compID)); + + const UInt width444 = dstPicYuvTop->getWidth(COMPONENT_Y) - (confLeft + confRight); + const UInt height444 = dstPicYuvTop->getHeight(COMPONENT_Y) - (confTop + confBottom); + + if ((width444 == 0) || (height444 == 0)) + { + printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444); + } + + const UInt csx = dstPicYuvTop->getComponentScaleX(compID); + const UInt csy = dstPicYuvTop->getComponentScaleY(compID); + const Int planeOffset = (confLeft>>csx) + ( confTop>>csy) * dstPicYuvTop->getStride(compID); //offset is for entire frame - round up for top field and down for bottom field + + if (! writeField(m_cHandle, + (dstPicYuvTop ->getAddr(compID) + planeOffset), + (dstPicYuvBottom->getAddr(compID) + planeOffset), + is16bit, + dstPicYuvTop->getStride(COMPONENT_Y), + width444, height444, compID, dstPicYuvTop->getChromaFormat(), format, m_fileBitdepth[ch], isTff)) + { + retval=false; + } + } + + if (nonZeroBitDepthShift) + { + dstPicYuvTop->destroy(); + dstPicYuvBottom->destroy(); + delete dstPicYuvTop; + delete dstPicYuvBottom; + } + + cPicYuvTopCSCd.destroy(); + cPicYuvBottomCSCd.destroy(); + + return retval; +} + +static Void +copyPlane(const TComPicYuv &src, const ComponentID srcPlane, TComPicYuv &dest, const ComponentID destPlane) +{ + const UInt width=src.getWidth(srcPlane); + const UInt height=src.getHeight(srcPlane); + assert(dest.getWidth(destPlane) == width); + assert(dest.getHeight(destPlane) == height); + const Pel *pSrc=src.getAddr(srcPlane); + Pel *pDest=dest.getAddr(destPlane); + const UInt strideSrc=src.getStride(srcPlane); + const UInt strideDest=dest.getStride(destPlane); + for(UInt y=0; y +#include +#include +#include "TLibCommon/CommonDef.h" +#include "TLibCommon/TComPicYuv.h" + +using namespace std; + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +/// YUV file I/O class +class TVideoIOYuv +{ +private: + fstream m_cHandle; ///< file handle + Int m_fileBitdepth[MAX_NUM_CHANNEL_TYPE]; ///< bitdepth of input/output video file + Int m_MSBExtendedBitDepth[MAX_NUM_CHANNEL_TYPE]; ///< bitdepth after addition of MSBs (with value 0) + Int m_bitdepthShift[MAX_NUM_CHANNEL_TYPE]; ///< number of bits to increase or decrease image by before/after write/read + +public: + TVideoIOYuv() {} + virtual ~TVideoIOYuv() {} + + Void open ( Char* pchFile, Bool bWriteMode, const Int fileBitDepth[MAX_NUM_CHANNEL_TYPE], const Int MSBExtendedBitDepth[MAX_NUM_CHANNEL_TYPE], const Int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ); ///< open or create file + Void close (); ///< close file + + Void skipFrames(UInt numFrames, UInt width, UInt height, ChromaFormat format); + + // if fileFormat +#include +#include "TAppEncTop.h" +#include "program_options_lite.h" + +//! \ingroup TAppEncoder +//! \{ + +#include "TLibCommon/Debug.h" + +// ==================================================================================================================== +// Main function +// ==================================================================================================================== + +int main(int argc, char* argv[]) +{ + TAppEncTop cTAppEncTop; + + // print information + fprintf( stdout, "\n" ); + fprintf( stdout, "HM software: Encoder Version [%s] (including RExt)", NV_VERSION ); + fprintf( stdout, NVM_ONOS ); + fprintf( stdout, NVM_COMPILEDBY ); + fprintf( stdout, NVM_BITS ); + fprintf( stdout, "\n\n" ); + + // create application encoder class + cTAppEncTop.create(); + + // parse configuration + try + { + if(!cTAppEncTop.parseCfg( argc, argv )) + { + cTAppEncTop.destroy(); +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + EnvVar::printEnvVar(); +#endif + return 1; + } + } + catch (df::program_options_lite::ParseFailure &e) + { + std::cerr << "Error parsing option \""<< e.arg <<"\" with argument \""<< e.val <<"\"." << std::endl; + return 1; + } + +#if PRINT_MACRO_VALUES + printMacroSettings(); +#endif + +#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST + EnvVar::printEnvVarInUse(); +#endif + + // starting time + Double dResult; + clock_t lBefore = clock(); + + // call encoding function + cTAppEncTop.encode(); + + // ending time + dResult = (Double)(clock()-lBefore) / CLOCKS_PER_SEC; + printf("\n Total Time: %12.3f sec.\n", dResult); + + // destroy application encoder class + cTAppEncTop.destroy(); + + return 0; +} + +//! \} diff --git a/jctvc/encoder_intra_main.cfg b/jctvc/encoder_intra_main.cfg new file mode 100644 index 0000000..6001865 --- /dev/null +++ b/jctvc/encoder_intra_main.cfg @@ -0,0 +1,103 @@ +#======== File I/O ===================== +BitstreamFile : str.bin +ReconFile : rec.yuv + +#======== Profile ================ +Profile : main-RExt +#Profile : main10 + +#======== Unit definition ================ +MaxCUWidth : 64 # Maximum coding unit width in pixel +MaxCUHeight : 64 # Maximum coding unit height in pixel +MaxPartitionDepth : 4 # Maximum coding unit depth +QuadtreeTULog2MaxSize : 5 # Log2 of maximum transform size for + # quadtree-based TU coding (2...6) +QuadtreeTULog2MinSize : 2 # Log2 of minimum transform size for + # quadtree-based TU coding (2...6) +QuadtreeTUMaxDepthInter : 3 +QuadtreeTUMaxDepthIntra : 3 + +#======== Coding Structure ============= +IntraPeriod : 1 # Period of I-Frame ( -1 = only first) +DecodingRefreshType : 0 # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI +GOPSize : 1 # GOP Size (number of B slice = GOPSize-1) +# Type POC QPoffset QPfactor tcOffsetDiv2 betaOffsetDiv2 temporal_id #ref_pics_active #ref_pics reference pictures + +#=========== Motion Search ============= +FastSearch : 1 # 0:Full search 1:TZ search +SearchRange : 64 # (0: Search range is a Full frame) +HadamardME : 1 # Use of hadamard measure for fractional ME +FEN : 1 # Fast encoder decision +FDM : 1 # Fast Decision for Merge RD cost + +#======== Quantization ============= +QP : 32 # Quantization parameter(0-51) +MaxDeltaQP : 0 # CU-based multi-QP optimization +MaxCuDQPDepth : 0 # Max depth of a minimum CuDQP for sub-LCU-level delta QP +DeltaQpRD : 0 # Slice-based multi-QP optimization +RDOQ : 1 # RDOQ +RDOQTS : 1 # RDOQ for transform skip + +#=========== Deblock Filter ============ +DeblockingFilterControlPresent: 0 # Dbl control params present (0=not present, 1=present) +LoopFilterOffsetInPPS : 0 # Dbl params: 0=varying params in SliceHeader, param = base_param + GOP_offset_param; 1=constant params in PPS, param = base_param) +LoopFilterDisable : 0 # Disable deblocking filter (0=Filter, 1=No Filter) +LoopFilterBetaOffset_div2 : 0 # base_param: -6 ~ 6 +LoopFilterTcOffset_div2 : 0 # base_param: -6 ~ 6 +DeblockingFilterMetric : 0 # blockiness metric (automatically configures deblocking parameters in bitstream) + +#=========== Misc. ============ +InternalBitDepth : 8 # codec operating bit-depth + +#=========== Coding Tools ================= +SAO : 1 # Sample adaptive offset (0: OFF, 1: ON) +AMP : 1 # Asymmetric motion partitions (0: OFF, 1: ON) +TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) +TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) + +#============ Slices ================ +SliceMode : 0 # 0: Disable all slice options. + # 1: Enforce maximum number of LCU in an slice, + # 2: Enforce maximum number of bytes in an 'slice' + # 3: Enforce maximum number of tiles in a slice +SliceArgument : 1500 # Argument for 'SliceMode'. + # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. + # If SliceMode==2 it represents max. bytes per slice. + # If SliceMode==3 it represents max. tiles per slice. + +LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. + # 0:not across, 1: across + +#============ PCM ================ +PCMEnabledFlag : 0 # 0: No PCM mode +PCMLog2MaxSize : 5 # Log2 of maximum PCM block size. +PCMLog2MinSize : 3 # Log2 of minimum PCM block size. +PCMInputBitDepthFlag : 1 # 0: PCM bit-depth is internal bit-depth. 1: PCM bit-depth is input bit-depth. +PCMFilterDisableFlag : 0 # 0: Enable loop filtering on I_PCM samples. 1: Disable loop filtering on I_PCM samples. + +#============ Tiles ================ +TileUniformSpacing : 0 # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array + # 1: the column and row boundaries are distributed uniformly +NumTileColumnsMinus1 : 0 # Number of tile columns in a picture minus 1 +TileColumnWidthArray : 2 3 # Array containing tile column width values in units of CTU (from left to right in picture) +NumTileRowsMinus1 : 0 # Number of tile rows in a picture minus 1 +TileRowHeightArray : 2 # Array containing tile row height values in units of CTU (from top to bottom in picture) + +LFCrossTileBoundaryFlag : 1 # In-loop filtering is across or not across tile boundary. + # 0:not across, 1: across + +#============ WaveFront ================ +WaveFrontSynchro : 0 # 0: No WaveFront synchronisation (WaveFrontSubstreams must be 1 in this case). + # >0: WaveFront synchronises with the LCU above and to the right by this many LCUs. + +#=========== Quantization Matrix ================= +ScalingList : 0 # ScalingList 0 : off, 1 : default, 2 : file read +ScalingListFile : scaling_list.txt # Scaling List file name. If file is not exist, use Default Matrix. + +#============ Lossless ================ +TransquantBypassEnableFlag : 0 # Value of PPS flag. +CUTransquantBypassFlagForce: 0 # Force transquant bypass mode, when transquant_bypass_enable_flag is enabled + +### DO NOT ADD ANYTHING BELOW THIS LINE ### +### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/jctvc/libmd5/MD5.h b/jctvc/libmd5/MD5.h new file mode 100644 index 0000000..a0a6e8a --- /dev/null +++ b/jctvc/libmd5/MD5.h @@ -0,0 +1,75 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once +#include "libmd5.h" +#include + +//! \ingroup libMD5 +//! \{ + +static const UInt MD5_DIGEST_STRING_LENGTH=16; + +class MD5 +{ +public: + /** + * initialize digest state + */ + MD5() + { + MD5Init(&m_state); + } + + /** + * compute digest over buf of length len. + * multiple calls may extend the digest over more data. + */ + void update(unsigned char *buf, unsigned len) + { + MD5Update(&m_state, buf, len); + } + + /** + * flush any outstanding MD5 data, write the digest into digest. + */ + void finalize(unsigned char digest[MD5_DIGEST_STRING_LENGTH]) + { + MD5Final(digest, &m_state); + } + +private: + context_md5_t m_state; +}; + + +//! \} diff --git a/jctvc/libmd5/libmd5.c b/jctvc/libmd5/libmd5.c new file mode 100644 index 0000000..2a699a1 --- /dev/null +++ b/jctvc/libmd5/libmd5.c @@ -0,0 +1,256 @@ +/* + * This code implements the MD5 message-digest algorithm. The algorithm was + * written by Ron Rivest. This code was written by Colin Plumb in 1993, our + * understanding is that no copyright is claimed and that this code is in the + * public domain. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is functionally equivalent, + * + * To compute the message digest of a chunk of bytes, declare an MD5Context + * structure, pass it to MD5Init, call MD5Update as needed on buffers full of + * bytes, and then call MD5Final, which will fill a supplied 16-byte array with + * the digest. + */ + +#include +#include +#include "libmd5.h" + +//! \ingroup libMD5 +//! \{ + +static void MD5Transform(uint32_t buf[4], uint32_t const in[16]); + +#ifndef __BIG_ENDIAN__ +# define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(uint32_t *buf, unsigned len); +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(uint32_t *buf, unsigned len) +{ + uint32_t t; + do { + char* bytes = (char *) buf; + t = ((unsigned) bytes[3] << 8 | bytes[2]) << 16 | + ((unsigned) bytes[1] << 8 | bytes[0]); + *buf = t; + buf++; + } while (--len); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(context_md5_t *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(context_md5_t *ctx, unsigned char *buf, unsigned len) +{ + uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = ctx->in.b8 + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in.b32, 16); + MD5Transform(ctx->buf, ctx->in.b32); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in.b8, buf, 64); + byteReverse(ctx->in.b32, 16); + MD5Transform(ctx->buf, ctx->in.b32); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in.b8, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], context_md5_t *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in.b8 + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in.b32, 16); + MD5Transform(ctx->buf, ctx->in.b32); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in.b8, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in.b32, 14); + + /* Append length in bits and transform */ + ctx->in.b32[14] = ctx->bits[0]; + ctx->in.b32[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, ctx->in.b32); + byteReverse((uint32_t *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + + memset(ctx, 0, sizeof(* ctx)); /* In case it's sensitive */ + /* The original version of this code omitted the asterisk. In + effect, only the first part of ctx was wiped with zeros, not + the whole thing. Bug found by Derek Jones. Original line: */ + // memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/jctvc/libmd5/libmd5.h b/jctvc/libmd5/libmd5.h new file mode 100644 index 0000000..d3569cd --- /dev/null +++ b/jctvc/libmd5/libmd5.h @@ -0,0 +1,58 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once +#include + +//! \ingroup libMD5 +//! \{ + +typedef struct _context_md5_t { + uint32_t buf[4]; + uint32_t bits[2]; + union { + unsigned char b8[64]; + uint32_t b32[16]; + } in; +} context_md5_t; + +#ifdef __cplusplus +extern "C" { +#endif +void MD5Init(context_md5_t *ctx); +void MD5Update(context_md5_t *ctx, unsigned char *buf, unsigned len); +void MD5Final(unsigned char digest[16], context_md5_t *ctx); +#ifdef __cplusplus +} +#endif + +//! \} diff --git a/jctvc/program_options_lite.cpp b/jctvc/program_options_lite.cpp new file mode 100644 index 0000000..7bc36ae --- /dev/null +++ b/jctvc/program_options_lite.cpp @@ -0,0 +1,498 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "program_options_lite.h" + +using namespace std; + +//! \ingroup TAppCommon +//! \{ + +namespace df +{ + namespace program_options_lite + { + + Options::~Options() + { + for(Options::NamesPtrList::iterator it = opt_list.begin(); it != opt_list.end(); it++) + { + delete *it; + } + } + + void Options::addOption(OptionBase *opt) + { + Names* names = new Names(); + names->opt = opt; + string& opt_string = opt->opt_string; + + size_t opt_start = 0; + for (size_t opt_end = 0; opt_end != string::npos;) + { + opt_end = opt_string.find_first_of(',', opt_start); + bool force_short = 0; + if (opt_string[opt_start] == '-') + { + opt_start++; + force_short = 1; + } + string opt_name = opt_string.substr(opt_start, opt_end - opt_start); + if (force_short || opt_name.size() == 1) + { + names->opt_short.push_back(opt_name); + opt_short_map[opt_name].push_back(names); + } + else + { + names->opt_long.push_back(opt_name); + opt_long_map[opt_name].push_back(names); + } + opt_start += opt_end + 1; + } + opt_list.push_back(names); + } + + /* Helper method to initiate adding options to Options */ + OptionSpecific Options::addOptions() + { + return OptionSpecific(*this); + } + + static void setOptions(Options::NamesPtrList& opt_list, const string& value) + { + /* multiple options may be registered for the same name: + * allow each to parse value */ + for (Options::NamesPtrList::iterator it = opt_list.begin(); it != opt_list.end(); ++it) + { + (*it)->opt->parse(value); + } + } + + static const char spaces[41] = " "; + + /* format help text for a single option: + * using the formatting: "-x, --long", + * if a short/long option isn't specified, it is not printed + */ + static void doHelpOpt(ostream& out, const Options::Names& entry, unsigned pad_short = 0) + { + pad_short = min(pad_short, 8u); + + if (!entry.opt_short.empty()) + { + unsigned pad = max((int)pad_short - (int)entry.opt_short.front().size(), 0); + out << "-" << entry.opt_short.front(); + if (!entry.opt_long.empty()) + { + out << ", "; + } + out << &(spaces[40 - pad]); + } + else + { + out << " "; + out << &(spaces[40 - pad_short]); + } + + if (!entry.opt_long.empty()) + { + out << "--" << entry.opt_long.front(); + } + } + + /* format the help text */ + void doHelp(ostream& out, Options& opts, unsigned columns) + { + const unsigned pad_short = 3; + /* first pass: work out the longest option name */ + unsigned max_width = 0; + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + ostringstream line(ios_base::out); + doHelpOpt(line, **it, pad_short); + max_width = max(max_width, (unsigned) line.tellp()); + } + + unsigned opt_width = min(max_width+2, 28u + pad_short) + 2; + unsigned desc_width = columns - opt_width; + + /* second pass: write out formatted option and help text. + * - align start of help text to start at opt_width + * - if the option text is longer than opt_width, place the help + * text at opt_width on the next line. + */ + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + ostringstream line(ios_base::out); + line << " "; + doHelpOpt(line, **it, pad_short); + + const string& opt_desc = (*it)->opt->opt_desc; + if (opt_desc.empty()) + { + /* no help text: output option, skip further processing */ + cout << line.str() << endl; + continue; + } + size_t currlength = size_t(line.tellp()); + if (currlength > opt_width) + { + /* if option text is too long (and would collide with the + * help text, split onto next line */ + line << endl; + currlength = 0; + } + /* split up the help text, taking into account new lines, + * (add opt_width of padding to each new line) */ + for (size_t newline_pos = 0, cur_pos = 0; cur_pos != string::npos; currlength = 0) + { + /* print any required padding space for vertical alignment */ + line << &(spaces[40 - opt_width + currlength]); + newline_pos = opt_desc.find_first_of('\n', newline_pos); + if (newline_pos != string::npos) + { + /* newline found, print substring (newline needn't be stripped) */ + newline_pos++; + line << opt_desc.substr(cur_pos, newline_pos - cur_pos); + cur_pos = newline_pos; + continue; + } + if (cur_pos + desc_width > opt_desc.size()) + { + /* no need to wrap text, remainder is less than avaliable width */ + line << opt_desc.substr(cur_pos); + break; + } + /* find a suitable point to split text (avoid spliting in middle of word) */ + size_t split_pos = opt_desc.find_last_of(' ', cur_pos + desc_width); + if (split_pos != string::npos) + { + /* eat up multiple space characters */ + split_pos = opt_desc.find_last_not_of(' ', split_pos) + 1; + } + + /* bad split if no suitable space to split at. fall back to width */ + bool bad_split = split_pos == string::npos || split_pos <= cur_pos; + if (bad_split) + { + split_pos = cur_pos + desc_width; + } + line << opt_desc.substr(cur_pos, split_pos - cur_pos); + + /* eat up any space for the start of the next line */ + if (!bad_split) + { + split_pos = opt_desc.find_first_not_of(' ', split_pos); + } + cur_pos = newline_pos = split_pos; + + if (cur_pos >= opt_desc.size()) + { + break; + } + line << endl; + } + + cout << line.str() << endl; + } + } + + bool storePair(Options& opts, bool allow_long, bool allow_short, const string& name, const string& value) + { + bool found = false; + Options::NamesMap::iterator opt_it; + if (allow_long) + { + opt_it = opts.opt_long_map.find(name); + if (opt_it != opts.opt_long_map.end()) + { + found = true; + } + } + + /* check for the short list */ + if (allow_short && !(found && allow_long)) + { + opt_it = opts.opt_short_map.find(name); + if (opt_it != opts.opt_short_map.end()) + { + found = true; + } + } + + if (!found) + { + /* not found */ + cerr << "Unknown option: `" << name << "' (value:`" << value << "')" << endl; + return false; + } + + setOptions((*opt_it).second, value); + return true; + } + + bool storePair(Options& opts, const string& name, const string& value) + { + return storePair(opts, true, true, name, value); + } + + /** + * returns number of extra arguments consumed + */ + unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]) + { + /* gnu style long options can take the forms: + * --option=arg + * --option arg + */ + string arg(argv[0]); + size_t arg_opt_start = arg.find_first_not_of('-'); + size_t arg_opt_sep = arg.find_first_of('='); + string option = arg.substr(arg_opt_start, arg_opt_sep - arg_opt_start); + + unsigned extra_argc_consumed = 0; + if (arg_opt_sep == string::npos) + { + /* no argument found => argument in argv[1] (maybe) */ + /* xxx, need to handle case where option isn't required */ +#if 0 + /* commented out, to return to true GNU style processing + * where longopts have to include an =, otherwise they are + * booleans */ + if (argc == 1) + return 0; /* run out of argv for argument */ + extra_argc_consumed = 1; +#endif + if(!storePair(opts, true, false, option, "1")) + { + return 0; + } + } + else + { + /* argument occurs after option_sep */ + string val = arg.substr(arg_opt_sep + 1); + storePair(opts, true, false, option, val); + } + + return extra_argc_consumed; + } + + unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]) + { + /* short options can take the forms: + * --option arg + * -option arg + */ + string arg(argv[0]); + size_t arg_opt_start = arg.find_first_not_of('-'); + string option = arg.substr(arg_opt_start); + /* lookup option */ + + /* argument in argv[1] */ + /* xxx, need to handle case where option isn't required */ + if (argc == 1) + { + cerr << "Not processing option without argument `" << option << "'" << endl; + return 0; /* run out of argv for argument */ + } + storePair(opts, false, true, option, string(argv[1])); + + return 1; + } + + list + scanArgv(Options& opts, unsigned argc, const char* argv[]) + { + /* a list for anything that didn't get handled as an option */ + list non_option_arguments; + + for(unsigned i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + { + non_option_arguments.push_back(argv[i]); + continue; + } + + if (argv[i][1] == 0) + { + /* a lone single dash is an argument (usually signifying stdin) */ + non_option_arguments.push_back(argv[i]); + continue; + } + + if (argv[i][1] != '-') + { + /* handle short (single dash) options */ +#if 0 + i += parsePOSIX(opts, argc - i, &argv[i]); +#else + i += parseSHORT(opts, argc - i, &argv[i]); +#endif + continue; + } + + if (argv[i][2] == 0) + { + /* a lone double dash ends option processing */ + while (++i < argc) + non_option_arguments.push_back(argv[i]); + break; + } + + /* handle long (double dash) options */ + i += parseGNU(opts, argc - i, &argv[i]); + } + + return non_option_arguments; + } + + void scanLine(Options& opts, string& line) + { + /* strip any leading whitespace */ + size_t start = line.find_first_not_of(" \t\n\r"); + if (start == string::npos) + { + /* blank line */ + return; + } + if (line[start] == '#') + { + /* comment line */ + return; + } + /* look for first whitespace or ':' after the option end */ + size_t option_end = line.find_first_of(": \t\n\r",start); + string option = line.substr(start, option_end - start); + + /* look for ':', eat up any whitespace first */ + start = line.find_first_not_of(" \t\n\r", option_end); + if (start == string::npos) + { + /* error: badly formatted line */ + return; + } + if (line[start] != ':') + { + /* error: badly formatted line */ + return; + } + + /* look for start of value string -- eat up any leading whitespace */ + start = line.find_first_not_of(" \t\n\r", ++start); + if (start == string::npos) + { + /* error: badly formatted line */ + return; + } + + /* extract the value part, which may contain embedded spaces + * by searching for a word at a time, until we hit a comment or end of line */ + size_t value_end = start; + do + { + if (line[value_end] == '#') + { + /* rest of line is a comment */ + value_end--; + break; + } + value_end = line.find_first_of(" \t\n\r", value_end); + /* consume any white space, incase there is another word. + * any trailing whitespace will be removed shortly */ + value_end = line.find_first_not_of(" \t\n\r", value_end); + } + while (value_end != string::npos); + /* strip any trailing space from value*/ + value_end = line.find_last_not_of(" \t\n\r", value_end); + + string value; + if (value_end >= start) + { + value = line.substr(start, value_end +1 - start); + } + else + { + /* error: no value */ + return; + } + + /* store the value in option */ + storePair(opts, true, false, option, value); + } + + void scanFile(Options& opts, istream& in) + { + do + { + string line; + getline(in, line); + scanLine(opts, line); + } + while(!!in); + } + + /* for all options in opts, set their storage to their specified + * default value */ + void setDefaults(Options& opts) + { + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + (*it)->opt->setDefault(); + } + } + + void parseConfigFile(Options& opts, const string& filename) + { + ifstream cfgstream(filename.c_str(), ifstream::in); + if (!cfgstream) + { + cerr << "Failed to open config file: `" << filename << "'" << endl; + exit(EXIT_FAILURE); + } + scanFile(opts, cfgstream); + } + + } +} + +//! \} diff --git a/jctvc/program_options_lite.h b/jctvc/program_options_lite.h new file mode 100644 index 0000000..b037e04 --- /dev/null +++ b/jctvc/program_options_lite.h @@ -0,0 +1,237 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2014, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#ifndef __PROGRAM_OPTIONS_LITE__ +#define __PROGRAM_OPTIONS_LITE__ + +//! \ingroup TAppCommon +//! \{ + + +namespace df +{ + namespace program_options_lite + { + struct Options; + + struct ParseFailure : public std::exception + { + ParseFailure(std::string arg0, std::string val0) throw() + : arg(arg0), val(val0) + {} + + ~ParseFailure() throw() {}; + + std::string arg; + std::string val; + + const char* what() const throw() { return "Option Parse Failure"; } + }; + + void doHelp(std::ostream& out, Options& opts, unsigned columns = 80); + unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]); + unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]); + std::list scanArgv(Options& opts, unsigned argc, const char* argv[]); + void scanLine(Options& opts, std::string& line); + void scanFile(Options& opts, std::istream& in); + void setDefaults(Options& opts); + void parseConfigFile(Options& opts, const std::string& filename); + bool storePair(Options& opts, const std::string& name, const std::string& value); + + /** OptionBase: Virtual base class for storing information relating to a + * specific option This base class describes common elements. Type specific + * information should be stored in a derived class. */ + struct OptionBase + { + OptionBase(const std::string& name, const std::string& desc) + : opt_string(name), opt_desc(desc) + {}; + + virtual ~OptionBase() {} + + /* parse argument arg, to obtain a value for the option */ + virtual void parse(const std::string& arg) = 0; + /* set the argument to the default value */ + virtual void setDefault() = 0; + + std::string opt_string; + std::string opt_desc; + }; + + /** Type specific option storage */ + template + struct Option : public OptionBase + { + Option(const std::string& name, T& storage, T default_val, const std::string& desc) + : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val) + {} + + void parse(const std::string& arg); + + void setDefault() + { + opt_storage = opt_default_val; + } + + T& opt_storage; + T opt_default_val; + }; + + /* Generic parsing */ + template + inline void + Option::parse(const std::string& arg) + { + std::istringstream arg_ss (arg,std::istringstream::in); + arg_ss.exceptions(std::ios::failbit); + try + { + arg_ss >> opt_storage; + } + catch (...) + { + throw ParseFailure(opt_string, arg); + } + } + + /* string parsing is specialized -- copy the whole string, not just the + * first word */ + template<> + inline void + Option::parse(const std::string& arg) + { + opt_storage = arg; + } + + /** Option class for argument handling using a user provided function */ + struct OptionFunc : public OptionBase + { + typedef void (Func)(Options&, const std::string&); + + OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc) + : OptionBase(name, desc), parent(parent_), func(func_) + {} + + void parse(const std::string& arg) + { + func(parent, arg); + } + + void setDefault() + { + return; + } + + private: + Options& parent; + void (*func)(Options&, const std::string&); + }; + + class OptionSpecific; + struct Options + { + ~Options(); + + OptionSpecific addOptions(); + + struct Names + { + Names() : opt(0) {}; + ~Names() + { + if (opt) + delete opt; + } + std::list opt_long; + std::list opt_short; + OptionBase* opt; + }; + + void addOption(OptionBase *opt); + + typedef std::list NamesPtrList; + NamesPtrList opt_list; + + typedef std::map NamesMap; + NamesMap opt_long_map; + NamesMap opt_short_map; + }; + + /* Class with templated overloaded operator(), for use by Options::addOptions() */ + class OptionSpecific + { + public: + OptionSpecific(Options& parent_) : parent(parent_) {} + + /** + * Add option described by name to the parent Options list, + * with storage for the option's value + * with default_val as the default value + * with desc as an optional help description + */ + template + OptionSpecific& + operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "") + { + parent.addOption(new Option(name, storage, default_val, desc)); + return *this; + } + + /** + * Add option described by name to the parent Options list, + * with desc as an optional help description + * instead of storing the value somewhere, a function of type + * OptionFunc::Func is called. It is upto this function to correctly + * handle evaluating the option's value. + */ + OptionSpecific& + operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "") + { + parent.addOption(new OptionFunc(name, parent, func, desc)); + return *this; + } + private: + Options& parent; + }; + + } /* namespace: program_options_lite */ +} /* namespace: df */ + +//! \} + +#endif diff --git a/jctvc_glue.cpp b/jctvc_glue.cpp new file mode 100644 index 0000000..6aa30b4 --- /dev/null +++ b/jctvc_glue.cpp @@ -0,0 +1,189 @@ +#ifdef WIN32 +#include +#endif +#include +#include +#include "TAppEncTop.h" +#include "TLibCommon/Debug.h" +#include "TLibEncoder/TEncAnalyze.h" + +#include "bpgenc.h" + +#define ARGV_MAX 128 + +static void add_opt(int *pargc, char **argv, + const char *str) +{ + int argc; + argc = *pargc; + if (argc >= ARGV_MAX) + abort(); + argv[argc++] = strdup(str); + *pargc = argc; +} + +/* return the encoded data in *pbuf and the size. Return < 0 if error */ +int jctvc_encode_picture(uint8_t **pbuf, Image *img, + const HEVCEncodeParams *params) +{ + TAppEncTop cTAppEncTop; + int argc; + char *argv[ARGV_MAX + 1]; + char buf[1024], infilename[1024], outfilename[1024]; + const char *str; + FILE *f; + uint8_t *out_buf; + int out_buf_len, i; + +#ifdef WIN32 + if (GetTempPath(sizeof(buf), buf) > sizeof(buf) - 1) { + fprintf(stderr, "Temporary path too long\n"); + return -1; + } +#else + strcpy(buf, "/tmp/"); +#endif + snprintf(infilename, sizeof(infilename), "%sout%d.yuv", buf, getpid()); + snprintf(outfilename, sizeof(outfilename), "%sout%d.bin", buf, getpid()); + + save_yuv(img, infilename); + + m_gcAnalyzeAll.clear(); + m_gcAnalyzeI.clear(); + m_gcAnalyzeP.clear(); + m_gcAnalyzeB.clear(); + m_gcAnalyzeAll_in.clear(); + + cTAppEncTop.create(); + + argc = 0; + add_opt(&argc, argv, "jctvc"); /* dummy executable name */ + + snprintf(buf, sizeof(buf),"--InputFile=%s", infilename); + add_opt(&argc, argv, buf); + snprintf(buf, sizeof(buf),"--BitstreamFile=%s", outfilename); + add_opt(&argc, argv, buf); + + snprintf(buf, sizeof(buf),"--SourceWidth=%d", img->w); + add_opt(&argc, argv, buf); + + snprintf(buf, sizeof(buf),"--SourceWidth=%d", img->w); + add_opt(&argc, argv, buf); + snprintf(buf, sizeof(buf),"--SourceHeight=%d", img->h); + add_opt(&argc, argv, buf); + snprintf(buf, sizeof(buf),"--InputBitDepth=%d", img->bit_depth); + add_opt(&argc, argv, buf); + + switch(img->format) { + case BPG_FORMAT_GRAY: + str = "400"; + break; + case BPG_FORMAT_420: + str = "420"; + break; + case BPG_FORMAT_422: + str = "422"; + break; + case BPG_FORMAT_444: + str = "444"; + break; + default: + abort(); + } + snprintf(buf, sizeof(buf),"--InputChromaFormat=%s", str); + add_opt(&argc, argv, buf); + + snprintf(buf, sizeof(buf),"--QP=%d", params->qp); + add_opt(&argc, argv, buf); + + snprintf(buf, sizeof(buf),"--SEIDecodedPictureHash=%d", + params->sei_decoded_picture_hash); + add_opt(&argc, argv, buf); + + if (!params->verbose) + add_opt(&argc, argv, "--Verbose=0"); + + /* single frame */ + add_opt(&argc, argv, "--FramesToBeEncoded=1"); + + /* no padding necessary (it is done before) */ + add_opt(&argc, argv, "--ConformanceWindowMode=0"); + + /* dummy frame rate */ + add_opt(&argc, argv, "--FrameRate=25"); + + /* general config */ + add_opt(&argc, argv, "--Profile=main_444_16_intra"); + + add_opt(&argc, argv, "--QuadtreeTULog2MaxSize=5"); + add_opt(&argc, argv, "--QuadtreeTUMaxDepthIntra=3"); + + add_opt(&argc, argv, "--IntraPeriod=1"); + add_opt(&argc, argv, "--GOPSize=1"); + add_opt(&argc, argv, "--TransformSkip=1"); + add_opt(&argc, argv, "--TransformSkipFast=1"); + + /* Note: Format Range extension */ + if (img->format == BPG_FORMAT_444) { + add_opt(&argc, argv, "--CrossComponentPrediction=1"); + } + + if (params->lossless) { + add_opt(&argc, argv, "--CostMode=lossless"); + add_opt(&argc, argv, "--SAO=0"); + add_opt(&argc, argv, "--LoopFilterDisable"); + add_opt(&argc, argv, "--TransquantBypassEnableFlag"); + add_opt(&argc, argv, "--CUTransquantBypassFlagForce"); + add_opt(&argc, argv, "--ImplicitResidualDPCM"); + add_opt(&argc, argv, "--GolombRiceParameterAdaptation"); + add_opt(&argc, argv, "--HadamardME=0"); + } + + /* trailing NULL */ + argv[argc] = NULL; + + if (params->verbose >= 2) { + int i; + printf("Encode options:"); + for(i = 0; i < argc; i++) { + printf(" %s", argv[i]); + } + printf("\n"); + } + + if(!cTAppEncTop.parseCfg( argc, argv )) { + fprintf(stderr, "Error while parsing options\n"); + cTAppEncTop.destroy(); + return -1; + } + + cTAppEncTop.encode(); + + cTAppEncTop.destroy(); + + for(i = 0; i < argc; i++) + free(argv[i]); + unlink(infilename); + + /* read output bitstream */ + f = fopen(outfilename, "rb"); + if (!f) { + fprintf(stderr, "Could not open '%s'\n", outfilename); + return -1; + } + + fseek(f, 0, SEEK_END); + out_buf_len = ftell(f); + fseek(f, 0, SEEK_SET); + out_buf = (uint8_t *)malloc(out_buf_len); + if (fread(out_buf, 1, out_buf_len, f) != out_buf_len) { + fprintf(stderr, "read error\n"); + fclose(f); + free(out_buf); + return -1; + } + fclose(f); + unlink(outfilename); + *pbuf = out_buf; + return out_buf_len; +} diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c new file mode 100644 index 0000000..d08abd8 --- /dev/null +++ b/libavcodec/allcodecs.c @@ -0,0 +1,592 @@ +/* + * Provide registration of all codecs, parsers and bitstream filters for libavcodec. + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Provide registration of all codecs, parsers and bitstream filters for libavcodec. + */ + +#include "config.h" +#include "avcodec.h" +#include "version.h" + +#define REGISTER_HWACCEL(X, x) \ + { \ + extern AVHWAccel ff_##x##_hwaccel; \ + if (CONFIG_##X##_HWACCEL) \ + av_register_hwaccel(&ff_##x##_hwaccel); \ + } + +#define REGISTER_ENCODER(X, x) \ + { \ + extern AVCodec ff_##x##_encoder; \ + if (CONFIG_##X##_ENCODER) \ + avcodec_register(&ff_##x##_encoder); \ + } + +#define REGISTER_DECODER(X, x) \ + { \ + extern AVCodec ff_##x##_decoder; \ + if (CONFIG_##X##_DECODER) \ + avcodec_register(&ff_##x##_decoder); \ + } + +#define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x) + +#define REGISTER_PARSER(X, x) \ + { \ + extern AVCodecParser ff_##x##_parser; \ + if (CONFIG_##X##_PARSER) \ + av_register_codec_parser(&ff_##x##_parser); \ + } + +#define REGISTER_BSF(X, x) \ + { \ + extern AVBitStreamFilter ff_##x##_bsf; \ + if (CONFIG_##X##_BSF) \ + av_register_bitstream_filter(&ff_##x##_bsf); \ + } + +void avcodec_register_all(void) +{ + static int initialized; + + if (initialized) + return; + initialized = 1; + + /* hardware accelerators */ + REGISTER_HWACCEL(H263_VAAPI, h263_vaapi); + REGISTER_HWACCEL(H263_VDPAU, h263_vdpau); + REGISTER_HWACCEL(H264_DXVA2, h264_dxva2); + REGISTER_HWACCEL(H264_VAAPI, h264_vaapi); + REGISTER_HWACCEL(H264_VDA, h264_vda); + REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old); + REGISTER_HWACCEL(H264_VDPAU, h264_vdpau); + REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc); + REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau); + REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc); + REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2); + REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi); + REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau); + REGISTER_HWACCEL(MPEG4_VAAPI, mpeg4_vaapi); + REGISTER_HWACCEL(MPEG4_VDPAU, mpeg4_vdpau); + REGISTER_HWACCEL(VC1_DXVA2, vc1_dxva2); + REGISTER_HWACCEL(VC1_VAAPI, vc1_vaapi); + REGISTER_HWACCEL(VC1_VDPAU, vc1_vdpau); + REGISTER_HWACCEL(WMV3_DXVA2, wmv3_dxva2); + REGISTER_HWACCEL(WMV3_VAAPI, wmv3_vaapi); + REGISTER_HWACCEL(WMV3_VDPAU, wmv3_vdpau); + + /* video codecs */ + REGISTER_ENCODER(A64MULTI, a64multi); + REGISTER_ENCODER(A64MULTI5, a64multi5); + REGISTER_DECODER(AASC, aasc); + REGISTER_DECODER(AIC, aic); + REGISTER_ENCDEC (ALIAS_PIX, alias_pix); + REGISTER_ENCDEC (AMV, amv); + REGISTER_DECODER(ANM, anm); + REGISTER_DECODER(ANSI, ansi); + REGISTER_ENCDEC (ASV1, asv1); + REGISTER_ENCDEC (ASV2, asv2); + REGISTER_DECODER(AURA, aura); + REGISTER_DECODER(AURA2, aura2); + REGISTER_ENCDEC (AVRP, avrp); + REGISTER_DECODER(AVRN, avrn); + REGISTER_DECODER(AVS, avs); + REGISTER_ENCDEC (AVUI, avui); + REGISTER_ENCDEC (AYUV, ayuv); + REGISTER_DECODER(BETHSOFTVID, bethsoftvid); + REGISTER_DECODER(BFI, bfi); + REGISTER_DECODER(BINK, bink); + REGISTER_ENCDEC (BMP, bmp); + REGISTER_DECODER(BMV_VIDEO, bmv_video); + REGISTER_DECODER(BRENDER_PIX, brender_pix); + REGISTER_DECODER(C93, c93); + REGISTER_DECODER(CAVS, cavs); + REGISTER_DECODER(CDGRAPHICS, cdgraphics); + REGISTER_DECODER(CDXL, cdxl); + REGISTER_ENCDEC (CINEPAK, cinepak); + REGISTER_ENCDEC (CLJR, cljr); + REGISTER_DECODER(CLLC, cllc); + REGISTER_ENCDEC (COMFORTNOISE, comfortnoise); + REGISTER_DECODER(CPIA, cpia); + REGISTER_DECODER(CSCD, cscd); + REGISTER_DECODER(CYUV, cyuv); + REGISTER_DECODER(DFA, dfa); + REGISTER_DECODER(DIRAC, dirac); + REGISTER_ENCDEC (DNXHD, dnxhd); + REGISTER_ENCDEC (DPX, dpx); + REGISTER_DECODER(DSICINVIDEO, dsicinvideo); + REGISTER_ENCDEC (DVVIDEO, dvvideo); + REGISTER_DECODER(DXA, dxa); + REGISTER_DECODER(DXTORY, dxtory); + REGISTER_DECODER(EACMV, eacmv); + REGISTER_DECODER(EAMAD, eamad); + REGISTER_DECODER(EATGQ, eatgq); + REGISTER_DECODER(EATGV, eatgv); + REGISTER_DECODER(EATQI, eatqi); + REGISTER_DECODER(EIGHTBPS, eightbps); + REGISTER_DECODER(EIGHTSVX_EXP, eightsvx_exp); + REGISTER_DECODER(EIGHTSVX_FIB, eightsvx_fib); + REGISTER_DECODER(ESCAPE124, escape124); + REGISTER_DECODER(ESCAPE130, escape130); + REGISTER_DECODER(EXR, exr); + REGISTER_ENCDEC (FFV1, ffv1); + REGISTER_ENCDEC (FFVHUFF, ffvhuff); + REGISTER_DECODER(FIC, fic); + REGISTER_ENCDEC (FLASHSV, flashsv); + REGISTER_ENCDEC (FLASHSV2, flashsv2); + REGISTER_DECODER(FLIC, flic); + REGISTER_ENCDEC (FLV, flv); + REGISTER_DECODER(FOURXM, fourxm); + REGISTER_DECODER(FRAPS, fraps); + REGISTER_DECODER(FRWU, frwu); + REGISTER_DECODER(G2M, g2m); + REGISTER_ENCDEC (GIF, gif); + REGISTER_ENCDEC (H261, h261); + REGISTER_ENCDEC (H263, h263); + REGISTER_DECODER(H263I, h263i); + REGISTER_ENCDEC (H263P, h263p); + REGISTER_DECODER(H264, h264); + REGISTER_DECODER(H264_CRYSTALHD, h264_crystalhd); + REGISTER_DECODER(H264_VDA, h264_vda); + REGISTER_DECODER(H264_VDPAU, h264_vdpau); + REGISTER_DECODER(HEVC, hevc); + REGISTER_DECODER(HNM4_VIDEO, hnm4_video); + REGISTER_ENCDEC (HUFFYUV, huffyuv); + REGISTER_DECODER(IDCIN, idcin); + REGISTER_DECODER(IFF_BYTERUN1, iff_byterun1); + REGISTER_DECODER(IFF_ILBM, iff_ilbm); + REGISTER_DECODER(INDEO2, indeo2); + REGISTER_DECODER(INDEO3, indeo3); + REGISTER_DECODER(INDEO4, indeo4); + REGISTER_DECODER(INDEO5, indeo5); + REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video); + REGISTER_ENCDEC (JPEG2000, jpeg2000); + REGISTER_ENCDEC (JPEGLS, jpegls); + REGISTER_DECODER(JV, jv); + REGISTER_DECODER(KGV1, kgv1); + REGISTER_DECODER(KMVC, kmvc); + REGISTER_DECODER(LAGARITH, lagarith); + REGISTER_ENCODER(LJPEG, ljpeg); + REGISTER_DECODER(LOCO, loco); + REGISTER_DECODER(MDEC, mdec); + REGISTER_DECODER(MIMIC, mimic); + REGISTER_ENCDEC (MJPEG, mjpeg); + REGISTER_DECODER(MJPEGB, mjpegb); + REGISTER_DECODER(MMVIDEO, mmvideo); + REGISTER_DECODER(MOTIONPIXELS, motionpixels); +#if FF_API_XVMC + REGISTER_DECODER(MPEG_XVMC, mpeg_xvmc); +#endif /* FF_API_XVMC */ + REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video); + REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video); + REGISTER_ENCDEC (MPEG4, mpeg4); + REGISTER_DECODER(MPEG4_CRYSTALHD, mpeg4_crystalhd); + REGISTER_DECODER(MPEG4_VDPAU, mpeg4_vdpau); + REGISTER_DECODER(MPEGVIDEO, mpegvideo); + REGISTER_DECODER(MPEG_VDPAU, mpeg_vdpau); + REGISTER_DECODER(MPEG1_VDPAU, mpeg1_vdpau); + REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd); + REGISTER_DECODER(MSA1, msa1); + REGISTER_DECODER(MSMPEG4_CRYSTALHD, msmpeg4_crystalhd); + REGISTER_DECODER(MSMPEG4V1, msmpeg4v1); + REGISTER_ENCDEC (MSMPEG4V2, msmpeg4v2); + REGISTER_ENCDEC (MSMPEG4V3, msmpeg4v3); + REGISTER_DECODER(MSRLE, msrle); + REGISTER_DECODER(MSS1, mss1); + REGISTER_DECODER(MSS2, mss2); + REGISTER_ENCDEC (MSVIDEO1, msvideo1); + REGISTER_DECODER(MSZH, mszh); + REGISTER_DECODER(MTS2, mts2); + REGISTER_DECODER(MVC1, mvc1); + REGISTER_DECODER(MVC2, mvc2); + REGISTER_DECODER(MXPEG, mxpeg); + REGISTER_DECODER(NUV, nuv); + REGISTER_DECODER(PAF_VIDEO, paf_video); + REGISTER_ENCDEC (PAM, pam); + REGISTER_ENCDEC (PBM, pbm); + REGISTER_ENCDEC (PCX, pcx); + REGISTER_ENCDEC (PGM, pgm); + REGISTER_ENCDEC (PGMYUV, pgmyuv); + REGISTER_DECODER(PICTOR, pictor); + REGISTER_ENCDEC (PNG, png); + REGISTER_ENCDEC (PPM, ppm); + REGISTER_ENCDEC (PRORES, prores); + REGISTER_ENCODER(PRORES_AW, prores_aw); + REGISTER_ENCODER(PRORES_KS, prores_ks); + REGISTER_DECODER(PRORES_LGPL, prores_lgpl); + REGISTER_DECODER(PTX, ptx); + REGISTER_DECODER(QDRAW, qdraw); + REGISTER_DECODER(QPEG, qpeg); + REGISTER_ENCDEC (QTRLE, qtrle); + REGISTER_ENCDEC (R10K, r10k); + REGISTER_ENCDEC (R210, r210); + REGISTER_ENCDEC (RAWVIDEO, rawvideo); + REGISTER_DECODER(RL2, rl2); + REGISTER_ENCDEC (ROQ, roq); + REGISTER_DECODER(RPZA, rpza); + REGISTER_ENCDEC (RV10, rv10); + REGISTER_ENCDEC (RV20, rv20); + REGISTER_DECODER(RV30, rv30); + REGISTER_DECODER(RV40, rv40); + REGISTER_ENCDEC (S302M, s302m); + REGISTER_DECODER(SANM, sanm); + REGISTER_ENCDEC (SGI, sgi); + REGISTER_DECODER(SGIRLE, sgirle); + REGISTER_DECODER(SMACKER, smacker); + REGISTER_DECODER(SMC, smc); + REGISTER_DECODER(SMVJPEG, smvjpeg); + REGISTER_ENCDEC (SNOW, snow); + REGISTER_DECODER(SP5X, sp5x); + REGISTER_ENCDEC (SUNRAST, sunrast); + REGISTER_ENCDEC (SVQ1, svq1); + REGISTER_DECODER(SVQ3, svq3); + REGISTER_ENCDEC (TARGA, targa); + REGISTER_DECODER(TARGA_Y216, targa_y216); + REGISTER_DECODER(THEORA, theora); + REGISTER_DECODER(THP, thp); + REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo); + REGISTER_ENCDEC (TIFF, tiff); + REGISTER_DECODER(TMV, tmv); + REGISTER_DECODER(TRUEMOTION1, truemotion1); + REGISTER_DECODER(TRUEMOTION2, truemotion2); + REGISTER_DECODER(TSCC, tscc); + REGISTER_DECODER(TSCC2, tscc2); + REGISTER_DECODER(TXD, txd); + REGISTER_DECODER(ULTI, ulti); + REGISTER_ENCDEC (UTVIDEO, utvideo); + REGISTER_ENCDEC (V210, v210); + REGISTER_DECODER(V210X, v210x); + REGISTER_ENCDEC (V308, v308); + REGISTER_ENCDEC (V408, v408); + REGISTER_ENCDEC (V410, v410); + REGISTER_DECODER(VB, vb); + REGISTER_DECODER(VBLE, vble); + REGISTER_DECODER(VC1, vc1); + REGISTER_DECODER(VC1_CRYSTALHD, vc1_crystalhd); + REGISTER_DECODER(VC1_VDPAU, vc1_vdpau); + REGISTER_DECODER(VC1IMAGE, vc1image); + REGISTER_DECODER(VCR1, vcr1); + REGISTER_DECODER(VMDVIDEO, vmdvideo); + REGISTER_DECODER(VMNC, vmnc); + REGISTER_DECODER(VP3, vp3); + REGISTER_DECODER(VP5, vp5); + REGISTER_DECODER(VP6, vp6); + REGISTER_DECODER(VP6A, vp6a); + REGISTER_DECODER(VP6F, vp6f); + REGISTER_DECODER(VP7, vp7); + REGISTER_DECODER(VP8, vp8); + REGISTER_DECODER(VP9, vp9); + REGISTER_DECODER(VQA, vqa); + REGISTER_DECODER(WEBP, webp); + REGISTER_ENCDEC (WMV1, wmv1); + REGISTER_ENCDEC (WMV2, wmv2); + REGISTER_DECODER(WMV3, wmv3); + REGISTER_DECODER(WMV3_CRYSTALHD, wmv3_crystalhd); + REGISTER_DECODER(WMV3_VDPAU, wmv3_vdpau); + REGISTER_DECODER(WMV3IMAGE, wmv3image); + REGISTER_DECODER(WNV1, wnv1); + REGISTER_DECODER(XAN_WC3, xan_wc3); + REGISTER_DECODER(XAN_WC4, xan_wc4); + REGISTER_ENCDEC (XBM, xbm); + REGISTER_ENCDEC (XFACE, xface); + REGISTER_DECODER(XL, xl); + REGISTER_ENCDEC (XWD, xwd); + REGISTER_ENCDEC (Y41P, y41p); + REGISTER_DECODER(YOP, yop); + REGISTER_ENCDEC (YUV4, yuv4); + REGISTER_DECODER(ZERO12V, zero12v); + REGISTER_DECODER(ZEROCODEC, zerocodec); + REGISTER_ENCDEC (ZLIB, zlib); + REGISTER_ENCDEC (ZMBV, zmbv); + + /* audio codecs */ + REGISTER_ENCDEC (AAC, aac); + REGISTER_DECODER(AAC_LATM, aac_latm); + REGISTER_ENCDEC (AC3, ac3); + REGISTER_ENCDEC (AC3_FIXED, ac3_fixed); + REGISTER_ENCDEC (ALAC, alac); + REGISTER_DECODER(ALS, als); + REGISTER_DECODER(AMRNB, amrnb); + REGISTER_DECODER(AMRWB, amrwb); + REGISTER_DECODER(APE, ape); + REGISTER_DECODER(ATRAC1, atrac1); + REGISTER_DECODER(ATRAC3, atrac3); + REGISTER_DECODER(ATRAC3P, atrac3p); + REGISTER_DECODER(BINKAUDIO_DCT, binkaudio_dct); + REGISTER_DECODER(BINKAUDIO_RDFT, binkaudio_rdft); + REGISTER_DECODER(BMV_AUDIO, bmv_audio); + REGISTER_DECODER(COOK, cook); + REGISTER_ENCDEC (DCA, dca); + REGISTER_DECODER(DSD_LSBF, dsd_lsbf); + REGISTER_DECODER(DSD_MSBF, dsd_msbf); + REGISTER_DECODER(DSD_LSBF_PLANAR, dsd_lsbf_planar); + REGISTER_DECODER(DSD_MSBF_PLANAR, dsd_msbf_planar); + REGISTER_DECODER(DSICINAUDIO, dsicinaudio); + REGISTER_ENCDEC (EAC3, eac3); + REGISTER_DECODER(EVRC, evrc); + REGISTER_DECODER(FFWAVESYNTH, ffwavesynth); + REGISTER_ENCDEC (FLAC, flac); + REGISTER_ENCDEC (G723_1, g723_1); + REGISTER_DECODER(G729, g729); + REGISTER_DECODER(GSM, gsm); + REGISTER_DECODER(GSM_MS, gsm_ms); + REGISTER_DECODER(IAC, iac); + REGISTER_DECODER(IMC, imc); + REGISTER_DECODER(MACE3, mace3); + REGISTER_DECODER(MACE6, mace6); + REGISTER_DECODER(METASOUND, metasound); + REGISTER_DECODER(MLP, mlp); + REGISTER_DECODER(MP1, mp1); + REGISTER_DECODER(MP1FLOAT, mp1float); + REGISTER_ENCDEC (MP2, mp2); + REGISTER_DECODER(MP2FLOAT, mp2float); + REGISTER_ENCODER(MP2FIXED, mp2fixed); + REGISTER_DECODER(MP3, mp3); + REGISTER_DECODER(MP3FLOAT, mp3float); + REGISTER_DECODER(MP3ADU, mp3adu); + REGISTER_DECODER(MP3ADUFLOAT, mp3adufloat); + REGISTER_DECODER(MP3ON4, mp3on4); + REGISTER_DECODER(MP3ON4FLOAT, mp3on4float); + REGISTER_DECODER(MPC7, mpc7); + REGISTER_DECODER(MPC8, mpc8); + REGISTER_ENCDEC (NELLYMOSER, nellymoser); + REGISTER_DECODER(ON2AVC, on2avc); + REGISTER_DECODER(OPUS, opus); + REGISTER_DECODER(PAF_AUDIO, paf_audio); + REGISTER_DECODER(QCELP, qcelp); + REGISTER_DECODER(QDM2, qdm2); + REGISTER_ENCDEC (RA_144, ra_144); + REGISTER_DECODER(RA_288, ra_288); + REGISTER_DECODER(RALF, ralf); + REGISTER_DECODER(SHORTEN, shorten); + REGISTER_DECODER(SIPR, sipr); + REGISTER_DECODER(SMACKAUD, smackaud); + REGISTER_ENCDEC (SONIC, sonic); + REGISTER_ENCODER(SONIC_LS, sonic_ls); + REGISTER_DECODER(TAK, tak); + REGISTER_DECODER(TRUEHD, truehd); + REGISTER_DECODER(TRUESPEECH, truespeech); + REGISTER_ENCDEC (TTA, tta); + REGISTER_DECODER(TWINVQ, twinvq); + REGISTER_DECODER(VMDAUDIO, vmdaudio); + REGISTER_ENCDEC (VORBIS, vorbis); + REGISTER_ENCDEC (WAVPACK, wavpack); + REGISTER_DECODER(WMALOSSLESS, wmalossless); + REGISTER_DECODER(WMAPRO, wmapro); + REGISTER_ENCDEC (WMAV1, wmav1); + REGISTER_ENCDEC (WMAV2, wmav2); + REGISTER_DECODER(WMAVOICE, wmavoice); + REGISTER_DECODER(WS_SND1, ws_snd1); + + /* PCM codecs */ + REGISTER_ENCDEC (PCM_ALAW, pcm_alaw); + REGISTER_DECODER(PCM_BLURAY, pcm_bluray); + REGISTER_DECODER(PCM_DVD, pcm_dvd); + REGISTER_ENCDEC (PCM_F32BE, pcm_f32be); + REGISTER_ENCDEC (PCM_F32LE, pcm_f32le); + REGISTER_ENCDEC (PCM_F64BE, pcm_f64be); + REGISTER_ENCDEC (PCM_F64LE, pcm_f64le); + REGISTER_DECODER(PCM_LXF, pcm_lxf); + REGISTER_ENCDEC (PCM_MULAW, pcm_mulaw); + REGISTER_ENCDEC (PCM_S8, pcm_s8); + REGISTER_ENCDEC (PCM_S8_PLANAR, pcm_s8_planar); + REGISTER_ENCDEC (PCM_S16BE, pcm_s16be); + REGISTER_ENCDEC (PCM_S16BE_PLANAR, pcm_s16be_planar); + REGISTER_ENCDEC (PCM_S16LE, pcm_s16le); + REGISTER_ENCDEC (PCM_S16LE_PLANAR, pcm_s16le_planar); + REGISTER_ENCDEC (PCM_S24BE, pcm_s24be); + REGISTER_ENCDEC (PCM_S24DAUD, pcm_s24daud); + REGISTER_ENCDEC (PCM_S24LE, pcm_s24le); + REGISTER_ENCDEC (PCM_S24LE_PLANAR, pcm_s24le_planar); + REGISTER_ENCDEC (PCM_S32BE, pcm_s32be); + REGISTER_ENCDEC (PCM_S32LE, pcm_s32le); + REGISTER_ENCDEC (PCM_S32LE_PLANAR, pcm_s32le_planar); + REGISTER_ENCDEC (PCM_U8, pcm_u8); + REGISTER_ENCDEC (PCM_U16BE, pcm_u16be); + REGISTER_ENCDEC (PCM_U16LE, pcm_u16le); + REGISTER_ENCDEC (PCM_U24BE, pcm_u24be); + REGISTER_ENCDEC (PCM_U24LE, pcm_u24le); + REGISTER_ENCDEC (PCM_U32BE, pcm_u32be); + REGISTER_ENCDEC (PCM_U32LE, pcm_u32le); + REGISTER_DECODER(PCM_ZORK, pcm_zork); + + /* DPCM codecs */ + REGISTER_DECODER(INTERPLAY_DPCM, interplay_dpcm); + REGISTER_ENCDEC (ROQ_DPCM, roq_dpcm); + REGISTER_DECODER(SOL_DPCM, sol_dpcm); + REGISTER_DECODER(XAN_DPCM, xan_dpcm); + + /* ADPCM codecs */ + REGISTER_DECODER(ADPCM_4XM, adpcm_4xm); + REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx); + REGISTER_DECODER(ADPCM_AFC, adpcm_afc); + REGISTER_DECODER(ADPCM_CT, adpcm_ct); + REGISTER_DECODER(ADPCM_DTK, adpcm_dtk); + REGISTER_DECODER(ADPCM_EA, adpcm_ea); + REGISTER_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa); + REGISTER_DECODER(ADPCM_EA_R1, adpcm_ea_r1); + REGISTER_DECODER(ADPCM_EA_R2, adpcm_ea_r2); + REGISTER_DECODER(ADPCM_EA_R3, adpcm_ea_r3); + REGISTER_DECODER(ADPCM_EA_XAS, adpcm_ea_xas); + REGISTER_ENCDEC (ADPCM_G722, adpcm_g722); + REGISTER_ENCDEC (ADPCM_G726, adpcm_g726); + REGISTER_DECODER(ADPCM_G726LE, adpcm_g726le); + REGISTER_DECODER(ADPCM_IMA_AMV, adpcm_ima_amv); + REGISTER_DECODER(ADPCM_IMA_APC, adpcm_ima_apc); + REGISTER_DECODER(ADPCM_IMA_DK3, adpcm_ima_dk3); + REGISTER_DECODER(ADPCM_IMA_DK4, adpcm_ima_dk4); + REGISTER_DECODER(ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs); + REGISTER_DECODER(ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead); + REGISTER_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss); + REGISTER_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki); + REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt); + REGISTER_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad); + REGISTER_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); + REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav); + REGISTER_DECODER(ADPCM_IMA_WS, adpcm_ima_ws); + REGISTER_ENCDEC (ADPCM_MS, adpcm_ms); + REGISTER_DECODER(ADPCM_SBPRO_2, adpcm_sbpro_2); + REGISTER_DECODER(ADPCM_SBPRO_3, adpcm_sbpro_3); + REGISTER_DECODER(ADPCM_SBPRO_4, adpcm_sbpro_4); + REGISTER_ENCDEC (ADPCM_SWF, adpcm_swf); + REGISTER_DECODER(ADPCM_THP, adpcm_thp); + REGISTER_DECODER(ADPCM_VIMA, adpcm_vima); + REGISTER_DECODER(ADPCM_XA, adpcm_xa); + REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha); + REGISTER_DECODER(VIMA, vima); + + /* subtitles */ + REGISTER_ENCDEC (SSA, ssa); + REGISTER_ENCDEC (ASS, ass); + REGISTER_ENCDEC (DVBSUB, dvbsub); + REGISTER_ENCDEC (DVDSUB, dvdsub); + REGISTER_DECODER(JACOSUB, jacosub); + REGISTER_DECODER(MICRODVD, microdvd); + REGISTER_ENCDEC (MOVTEXT, movtext); + REGISTER_DECODER(MPL2, mpl2); + REGISTER_DECODER(PGSSUB, pgssub); + REGISTER_DECODER(PJS, pjs); + REGISTER_DECODER(REALTEXT, realtext); + REGISTER_DECODER(SAMI, sami); + REGISTER_ENCDEC (SRT, srt); + REGISTER_DECODER(STL, stl); + REGISTER_ENCDEC (SUBRIP, subrip); + REGISTER_DECODER(SUBVIEWER, subviewer); + REGISTER_DECODER(SUBVIEWER1, subviewer1); + REGISTER_DECODER(TEXT, text); + REGISTER_DECODER(VPLAYER, vplayer); + REGISTER_ENCDEC (WEBVTT, webvtt); + REGISTER_ENCDEC (XSUB, xsub); + + /* external libraries */ + REGISTER_DECODER(LIBCELT, libcelt); + REGISTER_ENCODER(LIBFAAC, libfaac); + REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac); + REGISTER_ENCDEC (LIBGSM, libgsm); + REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms); + REGISTER_ENCDEC (LIBILBC, libilbc); + REGISTER_ENCODER(LIBMP3LAME, libmp3lame); + REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb); + REGISTER_DECODER(LIBOPENCORE_AMRWB, libopencore_amrwb); + REGISTER_ENCDEC (LIBOPENJPEG, libopenjpeg); + REGISTER_ENCDEC (LIBOPUS, libopus); + REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); + REGISTER_ENCODER(LIBSHINE, libshine); + REGISTER_ENCDEC (LIBSPEEX, libspeex); + REGISTER_DECODER(LIBSTAGEFRIGHT_H264, libstagefright_h264); + REGISTER_ENCODER(LIBTHEORA, libtheora); + REGISTER_ENCODER(LIBTWOLAME, libtwolame); + REGISTER_ENCDEC (LIBUTVIDEO, libutvideo); + REGISTER_ENCODER(LIBVO_AACENC, libvo_aacenc); + REGISTER_ENCODER(LIBVO_AMRWBENC, libvo_amrwbenc); + REGISTER_ENCDEC (LIBVORBIS, libvorbis); + REGISTER_ENCDEC (LIBVPX_VP8, libvpx_vp8); + REGISTER_ENCDEC (LIBVPX_VP9, libvpx_vp9); + REGISTER_ENCODER(LIBWAVPACK, libwavpack); + REGISTER_ENCODER(LIBWEBP, libwebp); + REGISTER_ENCODER(LIBX264, libx264); + REGISTER_ENCODER(LIBX264RGB, libx264rgb); + REGISTER_ENCODER(LIBX265, libx265); + REGISTER_ENCODER(LIBXAVS, libxavs); + REGISTER_ENCODER(LIBXVID, libxvid); + REGISTER_DECODER(LIBZVBI_TELETEXT, libzvbi_teletext); + REGISTER_ENCODER(LIBAACPLUS, libaacplus); + + /* text */ + REGISTER_DECODER(BINTEXT, bintext); + REGISTER_DECODER(XBIN, xbin); + REGISTER_DECODER(IDF, idf); + + /* parsers */ + REGISTER_PARSER(AAC, aac); + REGISTER_PARSER(AAC_LATM, aac_latm); + REGISTER_PARSER(AC3, ac3); + REGISTER_PARSER(ADX, adx); + REGISTER_PARSER(BMP, bmp); + REGISTER_PARSER(CAVSVIDEO, cavsvideo); + REGISTER_PARSER(COOK, cook); + REGISTER_PARSER(DCA, dca); + REGISTER_PARSER(DIRAC, dirac); + REGISTER_PARSER(DNXHD, dnxhd); + REGISTER_PARSER(DPX, dpx); + REGISTER_PARSER(DVBSUB, dvbsub); + REGISTER_PARSER(DVDSUB, dvdsub); + REGISTER_PARSER(DVD_NAV, dvd_nav); + REGISTER_PARSER(FLAC, flac); + REGISTER_PARSER(GSM, gsm); + REGISTER_PARSER(H261, h261); + REGISTER_PARSER(H263, h263); + REGISTER_PARSER(H264, h264); + REGISTER_PARSER(HEVC, hevc); + REGISTER_PARSER(MJPEG, mjpeg); + REGISTER_PARSER(MLP, mlp); + REGISTER_PARSER(MPEG4VIDEO, mpeg4video); + REGISTER_PARSER(MPEGAUDIO, mpegaudio); + REGISTER_PARSER(MPEGVIDEO, mpegvideo); + REGISTER_PARSER(OPUS, opus); + REGISTER_PARSER(PNG, png); + REGISTER_PARSER(PNM, pnm); + REGISTER_PARSER(RV30, rv30); + REGISTER_PARSER(RV40, rv40); + REGISTER_PARSER(TAK, tak); + REGISTER_PARSER(VC1, vc1); + REGISTER_PARSER(VORBIS, vorbis); + REGISTER_PARSER(VP3, vp3); + REGISTER_PARSER(VP8, vp8); + REGISTER_PARSER(VP9, vp9); + + /* bitstream filters */ + REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc); + REGISTER_BSF(CHOMP, chomp); + REGISTER_BSF(DUMP_EXTRADATA, dump_extradata); + REGISTER_BSF(H264_MP4TOANNEXB, h264_mp4toannexb); + REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header); + REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg); + REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header); + REGISTER_BSF(MP3_HEADER_DECOMPRESS, mp3_header_decompress); + REGISTER_BSF(MOV2TEXTSUB, mov2textsub); + REGISTER_BSF(NOISE, noise); + REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); + REGISTER_BSF(TEXT2MOVSUB, text2movsub); +} diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h new file mode 100644 index 0000000..97ff7d6 --- /dev/null +++ b/libavcodec/avcodec.h @@ -0,0 +1,5246 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVCODEC_H +#define AVCODEC_AVCODEC_H + +/** + * @file + * @ingroup libavc + * Libavcodec external API header + */ + +#include +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/cpu.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "version.h" + +/** + * @defgroup libavc Encoding/Decoding Library + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + * + */ + +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ + + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of a existing codec ID changes (that would break ABI), + * 2. Give it a value which when taken as ASCII is recognized uniquely by a human as this specific codec. + * This ensures that 2 forks can independently add AVCodecIDs without producing conflicts. + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + AV_CODEC_ID_MPEG2VIDEO_XVMC, +#endif /* FF_API_XVMC */ + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, + AV_CODEC_ID_IFF_BYTERUN1, + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130_DEPRECATED, + AV_CODEC_ID_G2M_DEPRECATED, + AV_CODEC_ID_WEBP_DEPRECATED, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC_DEPRECATED, + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX_DEPRECATED, + AV_CODEC_ID_PAF_VIDEO_DEPRECATED, + AV_CODEC_ID_EXR_DEPRECATED, + AV_CODEC_ID_VP7_DEPRECATED, + AV_CODEC_ID_SANM_DEPRECATED, + AV_CODEC_ID_SGIRLE_DEPRECATED, + AV_CODEC_ID_MVC1_DEPRECATED, + AV_CODEC_ID_MVC2_DEPRECATED, + + AV_CODEC_ID_BRENDER_PIX= MKBETAG('B','P','I','X'), + AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), + AV_CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), + AV_CODEC_ID_EXR = MKBETAG('0','E','X','R'), + AV_CODEC_ID_AVRP = MKBETAG('A','V','R','P'), + + AV_CODEC_ID_012V = MKBETAG('0','1','2','V'), + AV_CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'), + AV_CODEC_ID_AVUI = MKBETAG('A','V','U','I'), + AV_CODEC_ID_AYUV = MKBETAG('A','Y','U','V'), + AV_CODEC_ID_TARGA_Y216 = MKBETAG('T','2','1','6'), + AV_CODEC_ID_V308 = MKBETAG('V','3','0','8'), + AV_CODEC_ID_V408 = MKBETAG('V','4','0','8'), + AV_CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'), + AV_CODEC_ID_SANM = MKBETAG('S','A','N','M'), + AV_CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'), + AV_CODEC_ID_AVRN = MKBETAG('A','V','R','n'), + AV_CODEC_ID_CPIA = MKBETAG('C','P','I','A'), + AV_CODEC_ID_XFACE = MKBETAG('X','F','A','C'), + AV_CODEC_ID_SGIRLE = MKBETAG('S','G','I','R'), + AV_CODEC_ID_MVC1 = MKBETAG('M','V','C','1'), + AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'), + AV_CODEC_ID_SNOW = MKBETAG('S','N','O','W'), + AV_CODEC_ID_WEBP = MKBETAG('W','E','B','P'), + AV_CODEC_ID_SMVJPEG = MKBETAG('S','M','V','J'), + AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'), +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'), + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED, + AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED, + AV_CODEC_ID_PCM_S24LE_PLANAR = MKBETAG(24,'P','S','P'), + AV_CODEC_ID_PCM_S32LE_PLANAR = MKBETAG(32,'P','S','P'), + AV_CODEC_ID_PCM_S16BE_PLANAR = MKBETAG('P','S','P',16), + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA_DEPRECATED, + AV_CODEC_ID_ADPCM_VIMA = MKBETAG('V','I','M','A'), + AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'), + AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '), + AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '), + AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '), + AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '), + AV_CODEC_ID_ADPCM_G726LE = MKBETAG('6','2','7','G'), + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, +#if FF_API_VOXWARE + AV_CODEC_ID_VOXWARE, +#endif + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS_DEPRECATED, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK_DEPRECATED, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO_DEPRECATED, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'), + AV_CODEC_ID_SONIC = MKBETAG('S','O','N','C'), + AV_CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'), + AV_CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'), + AV_CODEC_ID_OPUS = MKBETAG('O','P','U','S'), + AV_CODEC_ID_TAK = MKBETAG('t','B','a','K'), + AV_CODEC_ID_EVRC = MKBETAG('s','e','v','c'), + AV_CODEC_ID_SMV = MKBETAG('s','s','m','v'), + AV_CODEC_ID_DSD_LSBF = MKBETAG('D','S','D','L'), + AV_CODEC_ID_DSD_MSBF = MKBETAG('D','S','D','M'), + AV_CODEC_ID_DSD_LSBF_PLANAR = MKBETAG('D','S','D','1'), + AV_CODEC_ID_DSD_MSBF_PLANAR = MKBETAG('D','S','D','8'), + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + AV_CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'), + AV_CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'), + AV_CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'), + AV_CODEC_ID_SAMI = MKBETAG('S','A','M','I'), + AV_CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'), + AV_CODEC_ID_STL = MKBETAG('S','p','T','L'), + AV_CODEC_ID_SUBVIEWER1 = MKBETAG('S','b','V','1'), + AV_CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'), + AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'), + AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'), + AV_CODEC_ID_MPL2 = MKBETAG('M','P','L','2'), + AV_CODEC_ID_VPLAYER = MKBETAG('V','P','l','r'), + AV_CODEC_ID_PJS = MKBETAG('P','h','J','S'), + AV_CODEC_ID_ASS = MKBETAG('A','S','S',' '), ///< ASS as defined in Matroska + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + AV_CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), + AV_CODEC_ID_XBIN = MKBETAG('X','B','I','N'), + AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), + AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), + AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'), + AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'), + AV_CODEC_ID_TIMED_ID3 = MKBETAG('T','I','D','3'), + AV_CODEC_ID_BIN_DATA = MKBETAG('D','A','T','A'), + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + +#if FF_API_CODEC_ID +#include "old_codec_ids.h" +#endif +}; + +/** + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_descriptor_get() + */ +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; + + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.
+ * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define FF_INPUT_BUFFER_PADDING_SIZE 32 + +/** + * @ingroup lavc_encoding + * minimum encoding buffer size + * Used to avoid some checks during header writing. + */ +#define FF_MIN_BUFFER_SIZE 16384 + + +/** + * @ingroup lavc_encoding + * motion estimation type. + */ +enum Motion_Est_ID { + ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed + ME_FULL, + ME_LOG, + ME_PHODS, + ME_EPZS, ///< enhanced predictive zonal search + ME_X1, ///< reserved for experiments + ME_HEX, ///< hexagon based search + ME_UMH, ///< uneven multi-hexagon search + ME_TESA, ///< transformed exhaustive search algorithm + ME_ITER=50, ///< iterative search +}; + +/** + * @ingroup lavc_decoding + */ +enum AVDiscard{ + /* We leave some space between them for extensions (drop some + * keyframes for intra-only or drop just some bidir frames). */ + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI +}; + +/** + * @ingroup lavc_encoding + */ +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // If this is 0 then quality_factor will be used instead. + float quality_factor; +} RcOverride; + +#if FF_API_MAX_BFRAMES +/** + * @deprecated there is no libavcodec-wide limit on the number of B-frames + */ +#define FF_MAX_B_FRAMES 16 +#endif + +/* encoding support + These flags can be passed in AVCodecContext.flags before initialization. + Note: Not everything is supported yet. +*/ + +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define CODEC_FLAG_UNALIGNED 0x0001 +#define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale. +#define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / advanced prediction for H.263. +#define CODEC_FLAG_OUTPUT_CORRUPT 0x0008 ///< Output even those frames that might be corrupted +#define CODEC_FLAG_QPEL 0x0010 ///< Use qpel MC. +#if FF_API_GMC +/** + * @deprecated use the "gmc" private option of the libxvid encoder + */ +#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. +#endif +#if FF_API_MV0 +/** + * @deprecated use the flag "mv0" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_MV0 0x0040 +#endif +#if FF_API_INPUT_PRESERVED +/** + * @deprecated passing reference-counted frames to the encoders replaces this + * flag + */ +#define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#endif +#define CODEC_FLAG_PASS1 0x0200 ///< Use internal 2pass ratecontrol in first pass mode. +#define CODEC_FLAG_PASS2 0x0400 ///< Use internal 2pass ratecontrol in second pass mode. +#define CODEC_FLAG_GRAY 0x2000 ///< Only decode/encode grayscale. +#if FF_API_EMU_EDGE +/** + * @deprecated edges are not used/required anymore. I.e. this flag is now always + * set. + */ +#define CODEC_FLAG_EMU_EDGE 0x4000 +#endif +#define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding. +#define CODEC_FLAG_TRUNCATED 0x00010000 /** Input bitstream might be truncated at a random + location instead of only at frame boundaries. */ +#if FF_API_NORMALIZE_AQP +/** + * @deprecated use the flag "naq" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 +#endif +#define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< Use interlaced DCT. +#define CODEC_FLAG_LOW_DELAY 0x00080000 ///< Force low delay. +#define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< Place global headers in extradata instead of every keyframe. +#define CODEC_FLAG_BITEXACT 0x00800000 ///< Use only bitexact stuff (except (I)DCT). +/* Fx : Flag for h263+ extra options */ +#define CODEC_FLAG_AC_PRED 0x01000000 ///< H.263 advanced intra coding / MPEG-4 AC prediction +#define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter +#define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation +#define CODEC_FLAG_CLOSED_GOP 0x80000000 +#define CODEC_FLAG2_FAST 0x00000001 ///< Allow non spec compliant speedup tricks. +#define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. +#define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. +#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format. DEPRECATED!!!! +#define CODEC_FLAG2_IGNORE_CROP 0x00010000 ///< Discard cropping information from SPS. + +#define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. +#define CODEC_FLAG2_SHOW_ALL 0x00400000 ///< Show all frames before the first keyframe +#define CODEC_FLAG2_EXPORT_MVS 0x10000000 ///< Export motion vectors through frame side data +#define CODEC_FLAG2_SKIP_MANUAL 0x20000000 ///< Do not skip samples and export skip information as frame side data + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +#define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 ///< Decoder can use draw_horiz_band callback. +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define CODEC_CAP_DR1 0x0002 +#define CODEC_CAP_TRUNCATED 0x0008 +#if FF_API_XVMC +/* Codec can export data for HW decoding. This flag indicates that + * the codec would call get_format() with list that might contain HW accelerated + * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them + * including raw image format. + * The application can use the passed context to determine bitstream version, + * chroma format, resolution etc. + */ +#define CODEC_CAP_HWACCEL 0x0010 +#endif /* FF_API_XVMC */ +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define CODEC_CAP_DELAY 0x0020 +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define CODEC_CAP_SMALL_LAST_FRAME 0x0040 +#if FF_API_CAP_VDPAU +/** + * Codec can export data for HW decoding (VDPAU). + */ +#define CODEC_CAP_HWACCEL_VDPAU 0x0080 +#endif +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carring such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define CODEC_CAP_SUBFRAMES 0x0100 +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define CODEC_CAP_EXPERIMENTAL 0x0200 +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define CODEC_CAP_CHANNEL_CONF 0x0400 +#if FF_API_NEG_LINESIZES +/** + * @deprecated no codecs use this capability + */ +#define CODEC_CAP_NEG_LINESIZES 0x0800 +#endif +/** + * Codec supports frame-level multithreading. + */ +#define CODEC_CAP_FRAME_THREADS 0x1000 +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define CODEC_CAP_SLICE_THREADS 0x2000 +/** + * Codec supports changed parameters at any point. + */ +#define CODEC_CAP_PARAM_CHANGE 0x4000 +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define CODEC_CAP_AUTO_THREADS 0x8000 +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define CODEC_CAP_VARIABLE_FRAME_SIZE 0x10000 +/** + * Codec is intra only. + */ +#define CODEC_CAP_INTRA_ONLY 0x40000000 +/** + * Codec is lossless. + */ +#define CODEC_CAP_LOSSLESS 0x80000000 + +#if FF_API_MB_TYPE +//The following defines may change, don't expect compatibility if you use them. +#define MB_TYPE_INTRA4x4 0x0001 +#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific +#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific +#define MB_TYPE_16x16 0x0008 +#define MB_TYPE_16x8 0x0010 +#define MB_TYPE_8x16 0x0020 +#define MB_TYPE_8x8 0x0040 +#define MB_TYPE_INTERLACED 0x0080 +#define MB_TYPE_DIRECT2 0x0100 //FIXME +#define MB_TYPE_ACPRED 0x0200 +#define MB_TYPE_GMC 0x0400 +#define MB_TYPE_SKIP 0x0800 +#define MB_TYPE_P0L0 0x1000 +#define MB_TYPE_P1L0 0x2000 +#define MB_TYPE_P0L1 0x4000 +#define MB_TYPE_P1L1 0x8000 +#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) +#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) +#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) +#define MB_TYPE_QUANT 0x00010000 +#define MB_TYPE_CBP 0x00020000 +//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) +#endif + +/** + * Pan Scan area. + * This specifies the area which should be displayed. + * Note there may be multiple such areas for one frame. + */ +typedef struct AVPanScan{ + /** + * id + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int16_t position[3][2]; +}AVPanScan; + +#if FF_API_QSCALE_TYPE +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 +#define FF_QSCALE_TYPE_H264 2 +#define FF_QSCALE_TYPE_VP56 3 +#endif + +#if FF_API_GET_BUFFER +#define FF_BUFFER_TYPE_INTERNAL 1 +#define FF_BUFFER_TYPE_USER 2 ///< direct rendering buffers (image is (de)allocated by user) +#define FF_BUFFER_TYPE_SHARED 4 ///< Buffer from somewhere else; don't deallocate image (data/base), all other tables are not shared. +#define FF_BUFFER_TYPE_COPY 8 ///< Just a (modified) copy of some other buffer, don't deallocate anything. + +#define FF_BUFFER_HINTS_VALID 0x01 // Buffer hints value is meaningful (if 0 ignore). +#define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer. +#define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer content. +#define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer (update). +#endif + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ +enum AVPacketSideDataType { + AV_PKT_DATA_PALETTE, + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) + * s32le channel_count + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) + * u64le channel_layout + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * Recommmends skipping the specified number of samples + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_PKT_DATA_SKIP_SAMPLES=70, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=mail/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, +}; + +typedef struct AVPacketSideData { + uint8_t *data; + int size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. + * + * AVPacket is one of the few structs in FFmpeg, whose size is a part of public + * ABI. Thus it may be allocated on stack and no new fields can be added to it + * without libavcodec and libavformat major bump. + * + * The semantics of data ownership depends on the buf or destruct (deprecated) + * fields. If either is set, the packet data is dynamically allocated and is + * valid indefinitely until av_free_packet() is called (which in turn calls + * av_buffer_unref()/the destruct callback to free the data). If neither is set, + * the packet data is typically backed by some static buffer somewhere and is + * only valid for a limited time (e.g. until the next read call when demuxing). + * + * The side data is always allocated with av_malloc() and is freed in + * av_free_packet(). + */ +typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; + /** + * Presentation timestamp in AVStream->time_base units; the time at which + * the decompressed packet will be presented to the user. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + * pts MUST be larger or equal to dts as presentation cannot happen before + * decompression, unless one wants to view hex dumps. Some formats misuse + * the terms dts and pts/cts to mean something different. Such timestamps + * must be converted to true pts/dts before they are stored in AVPacket. + */ + int64_t pts; + /** + * Decompression timestamp in AVStream->time_base units; the time at which + * the packet is decompressed. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + */ + int64_t dts; + uint8_t *data; + int size; + int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ + int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + + /** + * Duration of this packet in AVStream->time_base units, 0 if unknown. + * Equals next_pts - this_pts in presentation order. + */ + int duration; +#if FF_API_DESTRUCT_PACKET + attribute_deprecated + void (*destruct)(struct AVPacket *); + attribute_deprecated + void *priv; +#endif + int64_t pos; ///< byte position in stream, -1 if unknown + + /** + * Time difference in AVStream->time_base units from the pts of this + * packet to the point at which the output from the decoder has converged + * independent from the availability of previous frames. That is, the + * frames are virtually identical no matter if decoding started from + * the very first frame or from this keyframe. + * Is AV_NOPTS_VALUE if unknown. + * This field is not the display duration of the current packet. + * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY + * set. + * + * The purpose of this field is to allow seeking in streams that have no + * keyframes in the conventional sense. It corresponds to the + * recovery point SEI in H.264 and match_time_delta in NUT. It is also + * essential for some types of subtitle streams to ensure that all + * subtitles are correctly displayed after seeking. + */ + int64_t convergence_duration; +} AVPacket; +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002, + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; +/** + * @} + */ + +struct AVCodecInternal; + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; + +/** + * main external API structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. + * sizeof(AVCodecContext) must not be used outside libav*. + */ +typedef struct AVCodecContext { + /** + * information on struct for av_log + * - set by avcodec_alloc_context3 + */ + const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; +#if FF_API_CODEC_NAME + /** + * @deprecated this field is not used for anything in libavcodec + */ + attribute_deprecated + char codec_name[32]; +#endif + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + + /** + * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * - encoding: unused + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int stream_codec_tag; + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + // struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + + /** + * the average bitrate + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: Set by libavcodec. 0 or some bitrate if this info is available in the stream. + */ + int bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. + * - encoding: Set by user. + * - decoding: unused + */ + int global_quality; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + /** + * CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags; + + /** + * CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; + + /** + * some codecs need / can use extradata like Huffman tables. + * mjpeg: Huffman tables + * rv10: additional flags + * mpeg4: global headers (they can be in the bitstream or here) + * The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger + * than extradata_size to avoid problems if it is read with the bitstream reader. + * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * - encoding: Set/allocated/freed by libavcodec. + * - decoding: Set/allocated/freed by user. + */ + uint8_t *extradata; + int extradata_size; + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * This often, but not always is the inverse of the frame rate or field rate + * for video. + * - encoding: MUST be set by user. + * - decoding: the use of this field for decoding is deprecated. + * Use framerate instead. + */ + AVRational time_base; + + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + */ + int ticks_per_frame; + + /** + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this field is unused (see initial_padding). + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required. + */ + int coded_width, coded_height; + +#if FF_API_ASPECT_EXTENDED +#define FF_ASPECT_EXTENDED 15 +#endif + + /** + * the number of pictures in a group of pictures, or 0 for intra_only + * - encoding: Set by user. + * - decoding: unused + */ + int gop_size; + + /** + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. + * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec if known + */ + enum AVPixelFormat pix_fmt; + + /** + * Motion estimation algorithm used for video coding. + * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), + * 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific] + * - encoding: MUST be set by user. + * - decoding: unused + */ + int me_method; + + /** + * If non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw a horizontal band. It improves cache usage. Not + * all codecs can do that. You must check the codec capabilities + * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. + * The function is also used by hardware acceleration APIs. + * It is called at least once during frame decoding to pass + * the data needed for hardware render. + * In that mode instead of pixel data, AVFrame points to + * a structure specific to the acceleration API. The application + * reads the structure and can change some fields to indicate progress + * or mark state. + * - encoding: unused + * - decoding: Set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], + int y, int type, int height); + + /** + * callback to negotiate the pixelFormat + * @param fmt is the list of formats which are supported by the codec, + * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. + * The first is always the native one. + * @note The callback may be called again immediately if initialization for + * the selected (hardware-accelerated) pixel format failed. + * @warning Behavior is undefined if the callback returns a value not + * in the fmt list of formats. + * @return the chosen format + * - encoding: unused + * - decoding: Set by user, if not set the native format will be chosen. + */ + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + + /** + * maximum number of B-frames between non-B-frames + * Note: The output will be delayed by max_b_frames+1 relative to the input. + * - encoding: Set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between IP and B-frames + * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_factor; + + /** obsolete FIXME remove */ + int rc_strategy; +#define FF_RC_STRATEGY_XVID 1 + + int b_frame_strategy; + + /** + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + + /** + * 0-> h263 quant 1-> mpeg quant + * - encoding: Set by user. + * - decoding: unused + */ + int mpeg_quant; + + /** + * qscale factor between P and I-frames + * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * luminance masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float dark_masking; + + /** + * slice count + * - encoding: Set by libavcodec. + * - decoding: Set by user (or 0). + */ + int slice_count; + /** + * prediction method (needed for huffyuv) + * - encoding: Set by user. + * - decoding: unused + */ + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 + + /** + * slice offsets in the frame in bytes + * - encoding: Set/allocated by libavcodec. + * - decoding: Set/allocated by user (or NULL). + */ + int *slice_offset; + + /** + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVRational sample_aspect_ratio; + + /** + * motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock comparison function (not supported yet) + * - encoding: Set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced DCT comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. + * - decoding: unused + */ + int last_predictor_count; + + /** + * prepass for motion estimation + * - encoding: Set by user. + * - decoding: unused + */ + int pre_me; + + /** + * motion estimation prepass comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME prepass diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality + * - encoding: Set by user. + * - decoding: unused + */ + int me_subpel_quality; + +#if FF_API_AFD + /** + * DTG active format information (additional aspect ratio + * information only used in DVB MPEG-2 transport streams) + * 0 if not set. + * + * - encoding: unused + * - decoding: Set by decoder. + * @deprecated Deprecated in favor of AVSideData + */ + attribute_deprecated int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 +#endif /* FF_API_AFD */ + + /** + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_range; + + /** + * intra quantizer bias + * - encoding: Set by user. + * - decoding: unused + */ + int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 + + /** + * inter quantizer bias + * - encoding: Set by user. + * - decoding: unused + */ + int inter_quant_bias; + + /** + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + +#if FF_API_XVMC + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + * @deprecated XvMC doesn't need it anymore. + */ + attribute_deprecated int xvmc_acceleration; +#endif /* FF_API_XVMC */ + + /** + * macroblock decision mode + * - encoding: Set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *inter_matrix; + + /** + * scene change detection threshold + * 0 is default, larger means fewer detected scene changes. + * - encoding: Set by user. + * - decoding: unused + */ + int scenechange_threshold; + + /** + * noise reduction strength + * - encoding: Set by user. + * - decoding: unused + */ + int noise_reduction; + +#if FF_API_MPV_OPT + /** + * @deprecated this field is unused + */ + attribute_deprecated + int me_threshold; + + /** + * @deprecated this field is unused + */ + attribute_deprecated + int mb_threshold; +#endif + + /** + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: unused + */ + int intra_dc_precision; + + /** + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_top; + + /** + * Number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_bottom; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float border_masking; +#endif + + /** + * minimum MB lagrange multipler + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB lagrange multipler + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmax; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_penalty_compensation; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int bidir_refine; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int brd_scale; + + /** + * minimum GOP size + * - encoding: Set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. + */ + int refs; + + /** + * chroma qp offset from luma + * - encoding: Set by user. + * - decoding: unused + */ + int chromaoffset; + +#if FF_API_UNUSED_MEMBERS + /** + * Multiplied by qscale for each frame and added to scene_change_score. + * - encoding: Set by user. + * - decoding: unused + */ + attribute_deprecated int scenechange_factor; +#endif + + /** + * + * Note: Value depends upon the compare function used for fullpel ME. + * - encoding: Set by user. + * - decoding: unused + */ + int mv0_threshold; + + /** + * Adjust sensitivity of b_frame_strategy 1. + * - encoding: Set by user. + * - decoding: unused + */ + int b_sensitivity; + + /** + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorPrimaries color_primaries; + + /** + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + /** + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVChromaLocation chroma_sample_location; + + /** + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user + * - decoding: unused + */ + int slices; + + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. + */ + enum AVFieldOrder field_order; + + /* audio only */ + int sample_rate; ///< samples per second + int channels; ///< number of audio channels + + /** + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVSampleFormat sample_fmt; ///< sample format + + /* The following data should not be initialized. */ + /** + * Number of samples per channel in an audio frame. + * + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has CODEC_CAP_VARIABLE_FRAME_SIZE set, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size + */ + int frame_size; + + /** + * Frame counter, set by libavcodec. + * + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. + */ + int frame_number; + + /** + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. + */ + int block_align; + + /** + * Audio cutoff bandwidth (0 means "automatic") + * - encoding: Set by user. + * - decoding: unused + */ + int cutoff; + +#if FF_API_REQUEST_CHANNELS + /** + * Decoder should decode to this many channels if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. + * @deprecated Deprecated in favor of request_channel_layout. + */ + attribute_deprecated int request_channels; +#endif + + /** + * Audio channel layout. + * - encoding: set by user. + * - decoding: set by user, may be overwritten by libavcodec. + */ + uint64_t channel_layout; + + /** + * Request decoder to use this channel layout if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. + */ + uint64_t request_channel_layout; + + /** + * Type of service that the audio stream conveys. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVAudioServiceType audio_service_type; + + /** + * desired sample format + * - encoding: Not used. + * - decoding: Set by user. + * Decoder will decode to this format if it can. + */ + enum AVSampleFormat request_sample_fmt; + +#if FF_API_GET_BUFFER + /** + * Called at the beginning of each frame to get a buffer for it. + * + * The function will set AVFrame.data[], AVFrame.linesize[]. + * AVFrame.extended_data[] must also be set, but it should be the same as + * AVFrame.data[] except for planar audio with more channels than can fit + * in AVFrame.data[]. In that case, AVFrame.data[] shall still contain as + * many data pointers as it can hold. + * + * if CODEC_CAP_DR1 is not set then get_buffer() must call + * avcodec_default_get_buffer() instead of providing buffers allocated by + * some other means. + * + * AVFrame.data[] should be 32- or 16-byte-aligned unless the CPU doesn't + * need it. avcodec_default_get_buffer() aligns the output buffer properly, + * but if get_buffer() is overridden then alignment considerations should + * be taken into account. + * + * @see avcodec_default_get_buffer() + * + * Video: + * + * If pic.reference is set then the frame will be read later by libavcodec. + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * If frame multithreading is used and thread_safe_callbacks is set, + * it may be called from a different thread, but not from more than one at + * once. Does not need to be reentrant. + * + * @see release_buffer(), reget_buffer() + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * Decoders cannot use the buffer after returning from + * avcodec_decode_audio4(), so they will not call release_buffer(), as it + * is assumed to be released immediately upon return. In some rare cases, + * a decoder may need to call get_buffer() more than once in a single + * call to avcodec_decode_audio4(). In that case, when get_buffer() is + * called again after it has already been called once, the previously + * acquired buffer is assumed to be released at that time and may not be + * reused by the decoder. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + * + * @deprecated use get_buffer2() + */ + attribute_deprecated + int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * Called to release buffers which were allocated with get_buffer. + * A released buffer can be reused in get_buffer(). + * pic.data[*] must be set to NULL. + * May be called from a different thread if frame multithreading is used, + * but not by more than one thread at once, so does not need to be reentrant. + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + * + * @deprecated custom freeing callbacks should be set from get_buffer2() + */ + attribute_deprecated + void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * Called at the beginning of a frame to get cr buffer for it. + * Buffer type (size, hints) must be the same. libavcodec won't check it. + * libavcodec will pass previous buffer in pic, function should return + * same buffer or new buffer with old frame "painted" into it. + * If pic.data[0] == NULL must behave like get_buffer(). + * if CODEC_CAP_DR1 is not set then reget_buffer() must call + * avcodec_default_reget_buffer() instead of providing buffers allocated by + * some other means. + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + attribute_deprecated + int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); +#endif + + /** + * This callback is called at the beginning of each frame to get data + * buffer(s) for it. There may be one contiguous buffer for all the data or + * there may be a buffer per each data plane or anything in between. What + * this means is, you may set however many entries in buf[] you feel necessary. + * Each buffer must be reference-counted using the AVBuffer API (see description + * of buf[] below). + * + * The following fields will be set in the frame before this callback is + * called: + * - format + * - width, height (video only) + * - sample_rate, channel_layout, nb_samples (audio only) + * Their values may differ from the corresponding values in + * AVCodecContext. This callback must use the frame values, not the codec + * context values, to calculate the required buffer size. + * + * This callback must fill the following fields in the frame: + * - data[] + * - linesize[] + * - extended_data: + * * if the data is planar audio with more than 8 channels, then this + * callback must allocate and fill extended_data to contain all pointers + * to all data planes. data[] must hold as many pointers as it can. + * extended_data must be allocated with av_malloc() and will be freed in + * av_frame_unref(). + * * otherwise exended_data must point to data + * - buf[] must contain one or more pointers to AVBufferRef structures. Each of + * the frame's data and extended_data pointers must be contained in these. That + * is, one AVBufferRef for each allocated chunk of memory, not necessarily one + * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * - extended_buf and nb_extended_buf must be allocated with av_malloc() by + * this callback and filled with the extra buffers if there are more + * buffers than buf[] can hold. extended_buf will be freed in + * av_frame_unref(). + * + * If CODEC_CAP_DR1 is not set then get_buffer2() must call + * avcodec_default_get_buffer2() instead of providing buffers allocated by + * some other means. + * + * Each data plane must be aligned to the maximum required by the target + * CPU. + * + * @see avcodec_default_get_buffer2() + * + * Video: + * + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * Some decoders do not support linesizes changing between frames. + * + * If frame multithreading is used and thread_safe_callbacks is set, + * this callback may be called from a different thread, but not from more + * than one at once. Does not need to be reentrant. + * + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); + + /** + * If non-zero, the decoded audio and video frames returned from + * avcodec_decode_video2() and avcodec_decode_audio4() are reference-counted + * and are valid indefinitely. The caller must free them with + * av_frame_unref() when they are not needed anymore. + * Otherwise, the decoded frames must not be freed by the caller and are + * only valid until the next decode call. + * + * - encoding: unused + * - decoding: set by the caller before avcodec_open2(). + */ + int refcounted_frames; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames + * - encoding: Set by user. + * - decoding: unused + */ + int max_qdiff; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_qsquish; + + attribute_deprecated + float rc_qmod_amp; + attribute_deprecated + int rc_qmod_freq; +#endif + + /** + * decoder bitstream buffer size + * - encoding: Set by user. + * - decoding: unused + */ + int rc_buffer_size; + + /** + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + int rc_override_count; + RcOverride *rc_override; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + const char *rc_eq; +#endif + + /** + * maximum bitrate + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int rc_max_rate; + + /** + * minimum bitrate + * - encoding: Set by user. + * - decoding: unused + */ + int rc_min_rate; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_buffer_aggressivity; + + attribute_deprecated + float rc_initial_cplx; +#endif + + /** + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_max_available_vbv_use; + + /** + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_min_vbv_overflow_use; + + /** + * Number of bits which should be loaded into the rc buffer before decoding starts. + * - encoding: Set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 +#define FF_CODER_TYPE_RAW 2 +#define FF_CODER_TYPE_RLE 3 +#if FF_API_UNUSED_MEMBERS +#define FF_CODER_TYPE_DEFLATE 4 +#endif /* FF_API_UNUSED_MEMBERS */ + /** + * coder type + * - encoding: Set by user. + * - decoding: unused + */ + int coder_type; + + /** + * context model + * - encoding: Set by user. + * - decoding: unused + */ + int context_model; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmin; + + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmax; +#endif + + /** + * frame skip threshold + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_threshold; + + /** + * frame skip factor + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_factor; + + /** + * frame skip exponent + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_exp; + + /** + * frame skip comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_cmp; + + /** + * trellis RD quantization + * - encoding: Set by user. + * - decoding: unused + */ + int trellis; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int min_prediction_order; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int max_prediction_order; + + /** + * GOP timecode frame start number + * - encoding: Set by user, in non drop frame format + * - decoding: Set by libavcodec (timecode in the 25 bits format, -1 if unset) + */ + int64_t timecode_frame_start; + + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send. */ + /* It depends on the encoder if the data starts */ + /* with a Start Code (it should). H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload. */ + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); + + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do its best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263. */ + /* This doesn't take account of any particular */ + /* headers inside the transmitted RTP payload. */ + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int header_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int p_count; + int skip_count; + int misc_bits; + + /** + * number of bits used for the previously encoded frame + * - encoding: Set by libavcodec. + * - decoding: unused + */ + int frame_bits; + + /** + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + char *stats_in; + + /** + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#if FF_API_OLD_MSMPEG4 +#define FF_BUG_OLD_MSMPEG4 2 +#endif +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#if FF_API_AC_VLC +#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. +#endif +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 + + /** + * strictly follow the standard (MPEG4, ...). + * - encoding: Set by user. + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) + */ + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + + /** + * error concealment flags + * - encoding: unused + * - decoding: Set by user. + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 + + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#if FF_API_DEBUG_MV +/** + * @deprecated this option does nothing + */ +#define FF_DEBUG_MV 32 +#endif +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#if FF_API_UNUSED_MEMBERS +#define FF_DEBUG_PTS 0x00000200 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#if FF_API_DEBUG_MV +#define FF_DEBUG_VIS_QP 0x00002000 ///< only access through AVOptions from outside libavcodec +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 ///< only access through AVOptions from outside libavcodec +#endif +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_NOMC 0x01000000 + +#if FF_API_DEBUG_MV + /** + * debug + * Code outside libavcodec should access this field using AVOptions + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * Error recognition; may misdetect some more or less valid parts as errors. + * - encoding: unused + * - decoding: Set by user. + */ + int err_recognition; + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the codec) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error + + + /** + * opaque 64bit number (generally a PTS) that will be reordered and + * output in AVFrame.reordered_opaque + * - encoding: unused + * - decoding: Set by user. + */ + int64_t reordered_opaque; + + /** + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec + */ + struct AVHWAccel *hwaccel; + + /** + * Hardware accelerator context. + * For some hardware accelerators, a global context needs to be + * provided by the user. In that case, this holds display-dependent + * data FFmpeg cannot instantiate itself. Please refer to the + * FFmpeg HW accelerator documentation to know how to fill this + * is. e.g. for VA API, this is a struct vaapi_context. + * - encoding: unused + * - decoding: Set by user + */ + void *hwaccel_context; + + /** + * error + * - encoding: Set by libavcodec if flags&CODEC_FLAG_PSNR. + * - decoding: unused + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + + /** + * DCT algorithm, see FF_DCT_* below + * - encoding: Set by user. + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#if FF_API_UNUSED_MEMBERS +#define FF_DCT_INT 2 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 + + /** + * IDCT algorithm, see FF_IDCT_* below. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#if FF_API_ARCH_SH4 +#define FF_IDCT_SH4 9 +#endif +#define FF_IDCT_SIMPLEARM 10 +#if FF_API_UNUSED_MEMBERS +#define FF_IDCT_IPP 13 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_IDCT_XVID 14 +#if FF_API_IDCT_XVIDMMX +#define FF_IDCT_XVIDMMX 14 +#endif /* FF_API_IDCT_XVIDMMX */ +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#if FF_API_ARCH_SPARC +#define FF_IDCT_SIMPLEVIS 18 +#endif +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#if FF_API_ARCH_ALPHA +#define FF_IDCT_SIMPLEALPHA 23 +#endif +#define FF_IDCT_SIMPLEAUTO 128 + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. + */ + int bits_per_coded_sample; + + /** + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. + */ + int bits_per_raw_sample; + +#if FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) + */ + int lowres; +#endif + + /** + * the picture in the bitstream + * - encoding: Set by libavcodec. + * - decoding: unused + */ + AVFrame *coded_frame; + + /** + * thread count + * is used to decide how many independent tasks should be passed to execute() + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_count; + + /** + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. + */ + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once + + /** + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int active_thread_type; + + /** + * Set by the client if its custom get_buffer() callback can be called + * synchronously from another thread, which allows faster multithreaded decoding. + * draw_horiz_band() will be called from other threads regardless of this setting. + * Ignored if the default get_buffer() is used. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_safe_callbacks; + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + +#if FF_API_THREAD_OPAQUE + /** + * @deprecated this field should not be used from outside of lavc + */ + attribute_deprecated + void *thread_opaque; +#endif + + /** + * noise vs. sse weight for the nsse comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int nsse_weight; + + /** + * profile + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int profile; +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 0 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 1 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 2 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 + + /** + * level + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int level; +#define FF_LEVEL_UNKNOWN -99 + + /** + * Skip loop filtering for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * Skip IDCT/dequantization for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_idct; + + /** + * Skip decoding for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_frame; + + /** + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) + */ + uint8_t *subtitle_header; + int subtitle_header_size; + +#if FF_API_ERROR_RATE + /** + * @deprecated use the 'error_rate' private AVOption of the mpegvideo + * encoders + */ + attribute_deprecated + int error_rate; +#endif + +#if FF_API_CODEC_PKT + /** + * @deprecated this field is not supposed to be accessed from outside lavc + */ + attribute_deprecated + AVPacket *pkt; +#endif + + /** + * VBV delay coded in the last frame (in periods of a 27 MHz clock). + * Used for compliant TS muxing. + * - encoding: Set by libavcodec. + * - decoding: unused. + */ + uint64_t vbv_delay; + + /** + * Encoding only. Allow encoders to output packets that do not contain any + * encoded data, only side data. + * + * Some encoders need to output such packets, e.g. to update some stream + * parameters at the end of encoding. + * + * All callers are strongly recommended to set this option to 1 and update + * their code to deal with such packets, since this behaviour may become + * always enabled in the future (then this option will be deprecated and + * later removed). To avoid ABI issues when this happens, the callers should + * use AVOptions to set this field. + */ + int side_data_only_packets; + + /** + * Audio only. The number of "priming" samples (padding) inserted by the + * encoder at the beginning of the audio. I.e. this number of leading + * decoded samples must be discarded by the caller to get the original audio + * without leading padding. + * + * - decoding: unused + * - encoding: Set by libavcodec. The timestamps on the output packets are + * adjusted by the encoder so that they always refer to the + * first sample of the data actually contained in the packet, + * including any added padding. E.g. if the timebase is + * 1/samplerate and the timestamp of the first input sample is + * 0, the timestamp of the first output packet will be + * -initial_padding. + */ + int initial_padding; + + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: unused + */ + AVRational framerate; + + /** + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_pkt_timebase(avctx) + * - encoding unused. + * - decoding set by user. + */ + AVRational pkt_timebase; + + /** + * AVCodecDescriptor + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_codec_descriptor(avctx) + * - encoding: unused. + * - decoding: set by libavcodec. + */ + const AVCodecDescriptor *codec_descriptor; + +#if !FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) + */ + int lowres; +#endif + + /** + * Current statistics for PTS correction. + * - decoding: maintained and used by libavcodec, not intended to be used by user apps + * - encoding: unused + */ + int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far + int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far + int64_t pts_correction_last_pts; /// PTS of the last frame + int64_t pts_correction_last_dts; /// DTS of the last frame + + /** + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused + */ + char *sub_charenc; + + /** + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused + */ + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv + + /** + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * Code outside libavcodec should access this field using AVOptions + * + * - decoding: set by user + * - encoding: unused + */ + int skip_alpha; + + /** + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec + */ + int seek_preroll; + +#if !FF_API_DEBUG_MV + /** + * debug motion vectors + * Code outside libavcodec should access this field using AVOptions + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * custom intra quantization matrix + * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix() + * - encoding: Set by user, can be NULL. + * - decoding: unused. + */ + uint16_t *chroma_intra_matrix; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * Code outside libavcodec should access this field using AVOptions + * (NO direct access). + * - encoding: Set by user. + * - decoding: Set by user. + */ + uint8_t *dump_separator; + + /** + * ',' seperated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user through AVOPtions (NO direct access) + */ + char *codec_whitelist; +} AVCodecContext; + +AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); + +const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); + +int av_codec_get_lowres(const AVCodecContext *avctx); +void av_codec_set_lowres(AVCodecContext *avctx, int val); + +int av_codec_get_seek_preroll(const AVCodecContext *avctx); +void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); + +uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +typedef struct AVCodecDefault AVCodecDefault; + +struct AVSubtitle; + +/** + * AVCodec. + */ +typedef struct AVCodec { + /** + * Name of the codec implementation. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + * This is the primary way to find a codec from the user perspective. + */ + const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; + enum AVMediaType type; + enum AVCodecID id; + /** + * Codec capabilities. + * see CODEC_CAP_* + */ + int capabilities; + const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 + const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 + const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 +#if FF_API_LOWRES + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres() +#endif + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; + struct AVCodec *next; + /** + * @name Frame-level threading support functions + * @{ + */ + /** + * If defined, called on thread contexts when they are created. + * If the codec allocates writable tables in init(), re-allocate them here. + * priv_data will be set to a copy of the original. + */ + int (*init_thread_copy)(AVCodecContext *); + /** + * Copy necessary context variables from a previous thread context to the current one. + * If not defined, the next thread will start automatically; otherwise, the codec + * must call ff_thread_finish_setup(). + * + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. + */ + int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); + /** @} */ + + /** + * Private codec-specific defaults. + */ + const AVCodecDefault *defaults; + + /** + * Initialize codec static data, called from avcodec_register(). + */ + void (*init_static_data)(struct AVCodec *codec); + + int (*init)(AVCodecContext *); + int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, + const struct AVSubtitle *sub); + /** + * Encode data to an AVPacket. + * + * @param avctx codec context + * @param avpkt output AVPacket (may contain a user-provided buffer) + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in avpkt. + * @return 0 on success, negative error code on failure + */ + int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*close)(AVCodecContext *); + /** + * Flush buffers. + * Will be called when seeking + */ + void (*flush)(AVCodecContext *); +} AVCodec; + +int av_codec_get_max_lowres(const AVCodec *codec); + +struct MpegEncContext; + +/** + * @defgroup lavc_hwaccel AVHWAccel + * @{ + */ +typedef struct AVHWAccel { + /** + * Name of the hardware accelerated codec. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + */ + const char *name; + + /** + * Type of codec implemented by the hardware accelerator. + * + * See AVMEDIA_TYPE_xxx + */ + enum AVMediaType type; + + /** + * Codec implemented by the hardware accelerator. + * + * See AV_CODEC_ID_xxx + */ + enum AVCodecID id; + + /** + * Supported pixel format. + * + * Only hardware accelerated formats are supported here. + */ + enum AVPixelFormat pix_fmt; + + /** + * Hardware accelerated codec capabilities. + * see FF_HWACCEL_CODEC_CAP_* + */ + int capabilities; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVHWAccel *next; + + /** + * Allocate a custom buffer + */ + int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); + + /** + * Called at the beginning of each frame or field picture. + * + * Meaningful frame information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * + * Note that buf can be NULL along with buf_size set to 0. + * Otherwise, this means the whole frame is available at this point. + * + * @param avctx the codec context + * @param buf the frame data buffer base + * @param buf_size the size of the frame in bytes + * @return zero if successful, a negative value otherwise + */ + int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Callback for each slice. + * + * Meaningful slice information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * The only exception is XvMC, that works on MB level. + * + * @param avctx the codec context + * @param buf the slice data buffer base + * @param buf_size the size of the slice in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Called at the end of each frame or field picture. + * + * The whole picture is parsed at this point and can now be sent + * to the hardware accelerator. This function is mandatory. + * + * @param avctx the codec context + * @return zero if successful, a negative value otherwise + */ + int (*end_frame)(AVCodecContext *avctx); + + /** + * Size of per-frame hardware accelerator private data. + * + * Private data is allocated with av_mallocz() before + * AVCodecContext.get_buffer() and deallocated after + * AVCodecContext.release_buffer(). + */ + int frame_priv_data_size; + + /** + * Called for every Macroblock in a slice. + * + * XvMC uses it to replace the ff_mpv_decode_mb(). + * Instead of decoding to raw picture, MB parameters are + * stored in an array provided by the video driver. + * + * @param s the mpeg context + */ + void (*decode_mb)(struct MpegEncContext *s); + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ + int priv_data_size; +} AVHWAccel; + +/** + * Hardware acceleration should be used for decoding even if the codec level + * used is unknown or higher than the maximum supported level reported by the + * hardware driver. + */ +#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0) + +/** + * @} + */ + +/** + * @defgroup lavc_picture AVPicture + * + * Functions for working with AVPicture + * @{ + */ + +/** + * Picture data structure. + * + * Up to four components can be stored into it, the last component is + * alpha. + */ +typedef struct AVPicture { + uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes + int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line +} AVPicture; + +/** + * @} + */ + +enum AVSubtitleType { + SUBTITLE_NONE, + + SUBTITLE_BITMAP, ///< A bitmap, pict will be set + + /** + * Plain text, the text field must be set by the decoder and is + * authoritative. ass and pict fields may contain approximations. + */ + SUBTITLE_TEXT, + + /** + * Formatted text, the ass field must be set by the decoder and is + * authoritative. pict and text fields may contain approximations. + */ + SUBTITLE_ASS, +}; + +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + +typedef struct AVSubtitleRect { + int x; ///< top left corner of pict, undefined when pict is not set + int y; ///< top left corner of pict, undefined when pict is not set + int w; ///< width of pict, undefined when pict is not set + int h; ///< height of pict, undefined when pict is not set + int nb_colors; ///< number of colors in pict, undefined when pict is not set + + /** + * data+linesize for the bitmap of this subtitle. + * can be set for text/ass as well once they where rendered + */ + AVPicture pict; + enum AVSubtitleType type; + + char *text; ///< 0 terminated plain UTF-8 text + + /** + * 0 terminated ASS/SSA compatible event line. + * The presentation of this is unaffected by the other values in this + * struct. + */ + char *ass; + + int flags; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + unsigned num_rects; + AVSubtitleRect **rects; + int64_t pts; ///< Same as packet pts, in AV_TIME_BASE +} AVSubtitle; + +/** + * If c is NULL, returns the first registered codec, + * if c is non-NULL, returns the next registered codec after c, + * or NULL if c is the last one. + */ +AVCodec *av_codec_next(const AVCodec *c); + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); + +/** + * Return the libavcodec build-time configuration. + */ +const char *avcodec_configuration(void); + +/** + * Return the libavcodec license. + */ +const char *avcodec_license(void); + +/** + * Register the codec codec and initialize libavcodec. + * + * @warning either this function or avcodec_register_all() must be called + * before any other libavcodec functions. + * + * @see avcodec_register_all() + */ +void avcodec_register(AVCodec *codec); + +/** + * Register all the codecs, parsers and bitstream filters which were enabled at + * configuration time. If you do not call this function you can select exactly + * which formats you want to support, by using the individual registration + * functions. + * + * @see avcodec_register + * @see av_register_codec_parser + * @see av_register_bitstream_filter + */ +void avcodec_register_all(void); + +/** + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). + * + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + * @see avcodec_get_context_defaults + */ +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); + +/** + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. + */ +void avcodec_free_context(AVCodecContext **avctx); + +/** + * Set the fields of the given AVCodecContext to default values corresponding + * to the given codec (defaults may be codec-dependent). + * + * Do not call this function if a non-NULL codec has been passed + * to avcodec_alloc_context3() that allocated this AVCodecContext. + * If codec is non-NULL, it is illegal to call avcodec_open2() with a + * different codec on this AVCodecContext. + */ +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec); + +/** + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_class(void); + +/** + * Get the AVClass for AVFrame. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_frame_class(void); + +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); + +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open2() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context3(NULL), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + */ +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); + +#if FF_API_AVFRAME_LAVC +/** + * @deprecated use av_frame_alloc() + */ +attribute_deprecated +AVFrame *avcodec_alloc_frame(void); + +/** + * Set the fields of the given AVFrame to default values. + * + * @param frame The AVFrame of which the fields should be set to default values. + * + * @deprecated use av_frame_unref() + */ +attribute_deprecated +void avcodec_get_frame_defaults(AVFrame *frame); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. + * + * @param frame frame to be freed. The pointer will be set to NULL. + * + * @warning this function does NOT free the data buffers themselves + * (it does not know how, since they might have been allocated with + * a custom get_buffer()). + * + * @deprecated use av_frame_free() + */ +attribute_deprecated +void avcodec_free_frame(AVFrame **frame); +#endif + +/** + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * @warning This function is not thread safe! + * + * @code + * avcodec_register_all(); + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * avcodec_get_context_defaults3() for this context, then this + * parameter MUST be either NULL or equal to the previously passed + * codec. + * @param options A dictionary filled with AVCodecContext and codec-private options. + * On return this object will be filled with options that were not found. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_find(). + */ +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). + * + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() / + * avcodec_get_context_defaults3() with a non-NULL codec. Subsequent calls will + * do nothing. + */ +int avcodec_close(AVCodecContext *avctx); + +/** + * Free all allocated data in the given subtitle struct. + * + * @param sub AVSubtitle to free. + */ +void avsubtitle_free(AVSubtitle *sub); + +/** + * @} + */ + +/** + * @addtogroup lavc_packet + * @{ + */ + +#if FF_API_DESTRUCT_PACKET +/** + * Default packet destructor. + * @deprecated use the AVBuffer API instead + */ +attribute_deprecated +void av_destruct_packet(AVPacket *pkt); +#endif + +/** + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet + */ +void av_init_packet(AVPacket *pkt); + +/** + * Allocate the payload of a packet and initialize its fields with + * default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Reduce packet size, correctly zeroing padding + * + * @param pkt packet + * @param size new size + */ +void av_shrink_packet(AVPacket *pkt, int size); + +/** + * Increase packet size, correctly zeroing padding + * + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet + */ +int av_grow_packet(AVPacket *pkt, int grow_by); + +/** + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * buf and destruct fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + FF_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); + +/** + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated. + */ +int av_dup_packet(AVPacket *pkt); + +/** + * Copy packet, including contents + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet(AVPacket *dst, const AVPacket *src); + +/** + * Copy packet side data + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src); + +/** + * Free a packet. + * + * @param pkt packet to free + */ +void av_free_packet(AVPacket *pkt); + +/** + * Allocate new information of a packet. + * + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure + */ +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Get side information from packet. + * + * @param pkt packet + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int *size); + +int av_packet_merge_side_data(AVPacket *pkt); + +int av_packet_split_side_data(AVPacket *pkt); + +/** + * Pack a dictionary for use in side_data. + * + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure + */ +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict); + + +/** + * Convenience function to free all the side data stored. + * All the other fields stay untouched. + * + * @param pkt packet + */ +void av_packet_free_side_data(AVPacket *pkt); + +/** + * Setup a new reference to the data described by a given packet + * + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_packet_ref(AVPacket *dst, const AVPacket *src); + +/** + * Wipe the packet. + * + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. + */ +void av_packet_unref(AVPacket *pkt); + +/** + * Move every field in src to dst and reset src. + * + * @see av_packet_unref + * + * @param src Source packet, will be reset + * @param dst Destination packet + */ +void av_packet_move_ref(AVPacket *dst, AVPacket *src); + +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + * + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); + +/** + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. + * + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted + */ +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); + +/** + * @} + */ + +/** + * @addtogroup lavc_decoding + * @{ + */ + +/** + * Find a registered decoder with a matching codec ID. + * + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder(enum AVCodecID id); + +/** + * Find a registered decoder with the specified name. + * + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder_by_name(const char *name); + +#if FF_API_GET_BUFFER +attribute_deprecated int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); +attribute_deprecated void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); +attribute_deprecated int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); +#endif + +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); + +#if FF_API_EMU_EDGE +/** + * Return the amount of padding in pixels which the get_buffer callback must + * provide around the edge of the image for codecs which do not have the + * CODEC_FLAG_EMU_EDGE flag. + * + * @return Required padding in pixels. + * + * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer + * needed + */ +attribute_deprecated +unsigned avcodec_get_edge_width(void); +#endif + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you do not use any horizontal + * padding. + * + * May only be used if a codec with CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you also ensure that all + * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]); + +/** + * Converts AVChromaLocation to swscale x/y chroma position. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos); + +/** + * Converts swscale x/y chroma position to AVChromaLocation. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos); + +#if FF_API_OLD_DECODE_AUDIO +/** + * Wrapper function which calls avcodec_decode_audio4. + * + * @deprecated Use avcodec_decode_audio4 instead. + * + * Decode the audio frame of size avpkt->size from avpkt->data into samples. + * Some decoders may support multiple frames in a single AVPacket, such + * decoders would then just decode the first frame. In this case, + * avcodec_decode_audio3 has to be called again with an AVPacket that contains + * the remaining data in order to decode the second frame etc. + * If no frame + * could be outputted, frame_size_ptr is zero. Otherwise, it is the + * decompressed frame size in bytes. + * + * @warning You must set frame_size_ptr to the allocated size of the + * output buffer before calling avcodec_decode_audio3(). + * + * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer avpkt->data should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @warning You must not provide a custom get_buffer() when using + * avcodec_decode_audio3(). Doing so will override it with + * avcodec_default_get_buffer. Use avcodec_decode_audio4() instead, + * which does allow the application to provide a custom get_buffer(). + * + * @note You might have to align the input buffer avpkt->data and output buffer + * samples. The alignment requirements depend on the CPU: On some CPUs it isn't + * necessary at all, on others it won't work at all if not aligned and on others + * it will work but it will have an impact on performance. + * + * In practice, avpkt->data should have 4 byte alignment at minimum and + * samples should be 16 byte aligned unless the CPU doesn't need it + * (AltiVec and SSE do). + * + * @note Codecs which have the CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * + * @param avctx the codec context + * @param[out] samples the output buffer, sample type in avctx->sample_fmt + * If the sample format is planar, each channel plane will + * be the same size, with no padding between channels. + * @param[in,out] frame_size_ptr the output buffer size in bytes + * @param[in] avpkt The input AVPacket containing the input buffer. + * You can create such packet with av_init_packet() and by then setting + * data and size, some decoders might in addition need other fields. + * All decoders are designed to use the least fields possible though. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame data was decompressed (used) from the input AVPacket. + */ +attribute_deprecated int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, + int *frame_size_ptr, + AVPacket *avpkt); +#endif + +/** + * Decode the audio frame of size avpkt->size from avpkt->data into frame. + * + * Some decoders may support multiple frames in a single AVPacket. Such + * decoders would then just decode the first frame and the return value would be + * less than the packet size. In this case, avcodec_decode_audio4 has to be + * called again with an AVPacket containing the remaining data in order to + * decode the second frame, etc... Even if no frames are returned, the packet + * needs to be fed to the decoder with remaining data until it is completely + * consumed or an error occurs. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning samples. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no samples will be returned. + * + * @warning The input buffer, avpkt->data must be FF_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @param avctx the codec context + * @param[out] frame The AVFrame in which to store decoded audio samples. + * The decoder will allocate a buffer for the decoded frame by + * calling the AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is + * non-zero. Note that this field being set to zero + * does not mean that an error has occurred. For + * decoders with CODEC_CAP_DELAY set, no given decode + * call is guaranteed to produce a frame. + * @param[in] avpkt The input AVPacket containing the input buffer. + * At least avpkt->data and avpkt->size should be set. Some + * decoders might also require additional fields to be set. + * @return A negative error code is returned if an error occurred during + * decoding, otherwise the number of bytes consumed from the input + * AVPacket is returned. + */ +int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, const AVPacket *avpkt); + +/** + * Decode the video frame of size avpkt->size from avpkt->data into picture. + * Some decoders may support multiple frames in a single AVPacket, such + * decoders would then just decode the first frame. + * + * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note Codecs which have the CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * + * @param avctx the codec context + * @param[out] picture The AVFrame in which the decoded video frame will be stored. + * Use av_frame_alloc() to get an AVFrame. The codec will + * allocate memory for the actual bitmap by calling the + * AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * + * @param[in] avpkt The input AVPacket containing the input buffer. + * You can create such packet with av_init_packet() and by then setting + * data and size, some decoders might in addition need other fields like + * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least + * fields possible. + * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + */ +int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt); + +/** + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. + * If no subtitle could be decompressed, got_sub_ptr is zero. + * Otherwise, the subtitle is stored in *sub. + * Note that CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expect to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no subtitles will be returned. + * + * @param avctx the codec context + * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. + * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. + * @param[in] avpkt The input AVPacket containing the input buffer. + */ +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt); + +/** + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, //< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + + /** + * Time difference in stream time base units from the pts of this + * packet to the point at which the output from the decoder has converged + * independent from the availability of previous frames. That is, the + * frames are virtually identical no matter if decoding started from + * the very first frame or from this keyframe. + * Is AV_NOPTS_VALUE if unknown. + * This field is not the display duration of the current frame. + * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY + * set. + * + * The purpose of this field is to allow seeking in streams that have no + * keyframes in the conventional sense. It corresponds to the + * recovery point SEI in H.264 and match_time_delta in NUT. It is also + * essential for some types of subtitle streams to ensure that all + * subtitles are correctly displayed after seeking. + */ + int64_t convergence_duration; + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +AVCodecParser *av_parser_next(const AVCodecParser *c); + +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +/** + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitStreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +#if FF_API_OLD_ENCODE_AUDIO +/** + * Encode an audio frame from samples into buf. + * + * @deprecated Use avcodec_encode_audio2 instead. + * + * @note The output buffer should be at least FF_MIN_BUFFER_SIZE bytes large. + * However, for codecs with avctx->frame_size equal to 0 (e.g. PCM) the user + * will know how much space is needed because it depends on the value passed + * in buf_size as described below. In that case a lower value can be used. + * + * @param avctx the codec context + * @param[out] buf the output buffer + * @param[in] buf_size the output buffer size + * @param[in] samples the input buffer containing the samples + * The number of samples read from this buffer is frame_size*channels, + * both of which are defined in avctx. + * For codecs which have avctx->frame_size equal to 0 (e.g. PCM) the number of + * samples read from samples is equal to: + * buf_size * 8 / (avctx->channels * av_get_bits_per_sample(avctx->codec_id)) + * This also implies that av_get_bits_per_sample() must not return 0 for these + * codecs. + * @return On error a negative value is returned, on success zero or the number + * of bytes used to encode the data read from the input buffer. + */ +int attribute_deprecated avcodec_encode_audio(AVCodecContext *avctx, + uint8_t *buf, int buf_size, + const short *samples); +#endif + +/** + * Encode a frame of audio. + * + * Takes input samples from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay, split, and combine input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. If avpkt->data and + * avpkt->size are set, avpkt->destruct must also be set. All + * other AVPacket fields will be reset by the encoder using + * av_init_packet(). If avpkt->data is NULL, the encoder will + * allocate it. The encoder will set avpkt->size to the size + * of the output packet. + * + * If this function fails or produces no output, avpkt will be + * freed using av_free_packet() (i.e. avpkt->destruct will be + * called to free the user supplied buffer). + * @param[in] frame AVFrame containing the raw audio data to be encoded. + * May be NULL when flushing an encoder that has the + * CODEC_CAP_DELAY capability set. + * If CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +#if FF_API_OLD_ENCODE_VIDEO +/** + * @deprecated use avcodec_encode_video2() instead. + * + * Encode a video frame from pict into buf. + * The input picture should be + * stored using a specific format, namely avctx.pix_fmt. + * + * @param avctx the codec context + * @param[out] buf the output buffer for the bitstream of encoded frame + * @param[in] buf_size the size of the output buffer in bytes + * @param[in] pict the input picture to encode + * @return On error a negative value is returned, on success zero or the number + * of bytes used from the output buffer. + */ +attribute_deprecated +int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVFrame *pict); +#endif + +/** + * Encode a frame of video. + * + * Takes input raw video data from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay and reorder input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. All other AVPacket fields + * will be reset by the encoder using av_init_packet(). If + * avpkt->data is NULL, the encoder will allocate it. + * The encoder will set avpkt->size to the size of the + * output packet. The returned data (if any) belongs to the + * caller, he is responsible for freeing it. + * + * If this function fails or produces no output, avpkt will be + * freed using av_free_packet() (i.e. avpkt->destruct will be + * called to free the user supplied buffer). + * @param[in] frame AVFrame containing the raw video data to be encoded. + * May be NULL when flushing an encoder that has the + * CODEC_CAP_DELAY capability set. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + + +/** + * @} + */ + +#if FF_API_AVCODEC_RESAMPLE +/** + * @defgroup lavc_resample Audio resampling + * @ingroup libavc + * @deprecated use libswresample instead + * + * @{ + */ +struct ReSampleContext; +struct AVResampleContext; + +typedef struct ReSampleContext ReSampleContext; + +/** + * Initialize audio resampling context. + * + * @param output_channels number of output channels + * @param input_channels number of input channels + * @param output_rate output sample rate + * @param input_rate input sample rate + * @param sample_fmt_out requested output sample format + * @param sample_fmt_in input sample format + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear if 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + * @return allocated ReSampleContext, NULL if error occurred + */ +attribute_deprecated +ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate, + enum AVSampleFormat sample_fmt_out, + enum AVSampleFormat sample_fmt_in, + int filter_length, int log2_phase_count, + int linear, double cutoff); + +attribute_deprecated +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); + +/** + * Free resample context. + * + * @param s a non-NULL pointer to a resample context previously + * created with av_audio_resample_init() + */ +attribute_deprecated +void audio_resample_close(ReSampleContext *s); + + +/** + * Initialize an audio resampler. + * Note, if either rate is not an integer then simply scale both rates up so they are. + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear If 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + */ +attribute_deprecated +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); + +/** + * Resample an array of samples using a previously configured context. + * @param src an array of unconsumed samples + * @param consumed the number of samples of src which have been consumed are returned here + * @param src_size the number of unconsumed samples available + * @param dst_size the amount of space in samples available in dst + * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. + * @return the number of samples written in dst or -1 if an error occurred + */ +attribute_deprecated +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); + + +/** + * Compensate samplerate/timestamp drift. The compensation is done by changing + * the resampler parameters, so no audible clicks or similar distortions occur + * @param compensation_distance distance in output samples over which the compensation should be performed + * @param sample_delta number of output samples which should be output less + * + * example: av_resample_compensate(c, 10, 500) + * here instead of 510 samples only 500 samples would be output + * + * note, due to rounding the actual compensation might be slightly different, + * especially if the compensation_distance is large and the in_rate used during init is small + */ +attribute_deprecated +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +attribute_deprecated +void av_resample_close(struct AVResampleContext *c); + +/** + * @} + */ +#endif + +/** + * @addtogroup lavc_picture + * @{ + */ + +/** + * Allocate memory for the pixels of a picture and setup the AVPicture + * fields for it. + * + * Call avpicture_free() to free it. + * + * @param picture the picture structure to be filled in + * @param pix_fmt the pixel format of the picture + * @param width the width of the picture + * @param height the height of the picture + * @return zero if successful, a negative error code otherwise + * + * @see av_image_alloc(), avpicture_fill() + */ +int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Free a picture previously allocated by avpicture_alloc(). + * The data buffer used by the AVPicture is freed, but the AVPicture structure + * itself is not. + * + * @param picture the AVPicture to be freed + */ +void avpicture_free(AVPicture *picture); + +/** + * Setup the picture fields based on the specified image parameters + * and the provided image data buffer. + * + * The picture fields are filled in by using the image data buffer + * pointed to by ptr. + * + * If ptr is NULL, the function will fill only the picture linesize + * array and return the required size for the image buffer. + * + * To allocate an image buffer and fill the picture data in one call, + * use avpicture_alloc(). + * + * @param picture the picture to be filled in + * @param ptr buffer where the image data is stored, or NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @return the size in bytes required for src, a negative error code + * in case of failure + * + * @see av_image_fill_arrays() + */ +int avpicture_fill(AVPicture *picture, const uint8_t *ptr, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Copy pixel data from an AVPicture into a buffer. + * + * avpicture_get_size() can be used to compute the required size for + * the buffer to fill. + * + * @param src source picture with filled data + * @param pix_fmt picture pixel format + * @param width picture width + * @param height picture height + * @param dest destination buffer + * @param dest_size destination buffer size in bytes + * @return the number of bytes written to dest, or a negative value + * (error code) on error, for example if the destination buffer is not + * big enough + * + * @see av_image_copy_to_buffer() + */ +int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt, + int width, int height, + unsigned char *dest, int dest_size); + +/** + * Calculate the size in bytes that a picture of the given width and height + * would occupy if stored in the given picture format. + * + * @param pix_fmt picture pixel format + * @param width picture width + * @param height picture height + * @return the computed picture buffer size or a negative error code + * in case of error + * + * @see av_image_get_buffer_size(). + */ +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height); + +#if FF_API_DEINTERLACE +/** + * deinterlace - if not supported return -1 + * + * @deprecated - use yadif (in libavfilter) instead + */ +attribute_deprecated +int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); +#endif +/** + * Copy image src to dst. Wraps av_image_copy(). + */ +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Crop image top and left side. + */ +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band); + +/** + * Pad image. + */ +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +/** + * @} + */ + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample + * for one that returns a failure code and continues in case of invalid + * pix_fmts. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @see av_pix_fmt_get_chroma_sub_sample + */ + +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift); + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); + +/** + * @deprecated see av_get_pix_fmt_loss() + */ +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Find the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); + +/** + * @deprecated see av_find_best_pix_fmt_of_2() + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +attribute_deprecated +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI +enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); +#else +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); +#endif + + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + +/** + * @} + */ + +#if FF_API_SET_DIMENSIONS +/** + * @deprecated this function is not supposed to be used from outside of lavc + */ +attribute_deprecated +void avcodec_set_dimensions(AVCodecContext *s, int width, int height); +#endif + +/** + * Put a string representing the codec tag codec_tag in buf. + * + * @param buf buffer to place codec tag in + * @param buf_size size in bytes of buf + * @param codec_tag codec tag to assign + * @return the length of the string that would have been generated if + * enough space had been available, excluding the trailing null + */ +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef + +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); + +/** + * Reset the internal decoder state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. + * + * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0), + * this invalidates the frames previously returned from the decoder. When + * refcounted frames are used, the decoder just releases any references it might + * keep internally, but the caller's reference remains valid. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); + + +typedef struct AVBitStreamFilterContext { + void *priv_data; + struct AVBitStreamFilter *filter; + AVCodecParserContext *parser; + struct AVBitStreamFilterContext *next; +} AVBitStreamFilterContext; + + +typedef struct AVBitStreamFilter { + const char *name; + int priv_data_size; + int (*filter)(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + void (*close)(AVBitStreamFilterContext *bsfc); + struct AVBitStreamFilter *next; +} AVBitStreamFilter; + +/** + * Register a bitstream filter. + * + * The filter will be accessible to the application code through + * av_bitstream_filter_next() or can be directly initialized with + * av_bitstream_filter_init(). + * + * @see avcodec_register_all() + */ +void av_register_bitstream_filter(AVBitStreamFilter *bsf); + +/** + * Create and initialize a bitstream filter context given a bitstream + * filter name. + * + * The returned context must be freed with av_bitstream_filter_close(). + * + * @param name the name of the bitstream filter + * @return a bitstream filter context if a matching filter was found + * and successfully initialized, NULL otherwise + */ +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); + +/** + * Filter bitstream. + * + * This function filters the buffer buf with size buf_size, and places the + * filtered buffer in the buffer pointed to by poutbuf. + * + * The output buffer must be freed by the caller. + * + * @param bsfc bitstream filter context created by av_bitstream_filter_init() + * @param avctx AVCodecContext accessed by the filter, may be NULL. + * If specified, this must point to the encoder context of the + * output stream the packet is sent to. + * @param args arguments which specify the filter configuration, may be NULL + * @param poutbuf pointer which is updated to point to the filtered buffer + * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes + * @param buf buffer containing the data to filter + * @param buf_size size in bytes of buf + * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data + * @return >= 0 in case of success, or a negative error code in case of failure + * + * If the return value is positive, an output buffer is allocated and + * is available in *poutbuf, and is distinct from the input buffer. + * + * If the return value is 0, the output buffer is not allocated and + * should be considered identical to the input buffer, or in case + * *poutbuf was set it points to the input buffer (not necessarily to + * its starting address). + */ +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + +/** + * Release bitstream filter context. + * + * @param bsf the bitstream filter context created with + * av_bitstream_filter_init(), can be NULL + */ +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); + +/** + * If f is NULL, return the first registered bitstream filter, + * if f is non-NULL, return the next registered bitstream filter + * after f, or NULL if f is the last one. + * + * This function can be used to iterate over all registered bitstream + * filters. + */ +AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); + +/* memory */ + +/** + * Same behaviour av_fast_malloc but the buffer has additional + * FF_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. + */ +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. + */ +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#if FF_API_MISSING_SAMPLE +/** + * Log a generic warning message about a missing feature. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] feature string containing the name of the missing feature + * @param[in] want_sample indicates if samples are wanted which exhibit this feature. + * If want_sample is non-zero, additional verbage will be added to the log + * message which tells the user how to report samples to the development + * mailing list. + * @deprecated Use avpriv_report_missing_feature() instead. + */ +attribute_deprecated +void av_log_missing_feature(void *avc, const char *feature, int want_sample); + +/** + * Log a generic warning message asking for a sample. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing an optional message, or NULL if no message + * @deprecated Use avpriv_request_sample() instead. + */ +attribute_deprecated +void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); +#endif /* FF_API_MISSING_SAMPLE */ + +/** + * Register the hardware accelerator hwaccel. + */ +void av_register_hwaccel(AVHWAccel *hwaccel); + +/** + * If hwaccel is NULL, returns the first registered hardware accelerator, + * if hwaccel is non-NULL, returns the next registered hardware accelerator + * after hwaccel, or NULL if hwaccel is the last one. + */ +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); + + +/** + * Lock operation used by lockmgr + */ +enum AVLockOp { + AV_LOCK_CREATE, ///< Create a mutex + AV_LOCK_OBTAIN, ///< Lock the mutex + AV_LOCK_RELEASE, ///< Unlock the mutex + AV_LOCK_DESTROY, ///< Free mutex resources +}; + +/** + * Register a user provided lock manager supporting the operations + * specified by AVLockOp. The "mutex" argument to the function points + * to a (void *) where the lockmgr should store/get a pointer to a user + * allocated mutex. It is NULL upon AV_LOCK_CREATE and equal to the + * value left by the last call for all other ops. If the lock manager is + * unable to perform the op then it should leave the mutex in the same + * state as when it was called and return a non-zero value. However, + * when called with AV_LOCK_DESTROY the mutex will always be assumed to + * have been successfully destroyed. If av_lockmgr_register succeeds + * it will return a non-negative value, if it fails it will return a + * negative value and destroy all mutex and unregister all callbacks. + * av_lockmgr_register is not thread-safe, it must be called from a + * single thread before any calls which make use of locking are used. + * + * @param cb User defined callback. av_lockmgr_register invokes calls + * to this callback and the previously registered callback. + * The callback will be used to create more than one mutex + * each of which must be backed by its own underlying locking + * mechanism (i.e. do not use a single static object to + * implement your lock manager). If cb is set to NULL the + * lockmgr will be unregistered. + */ +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * @} + */ + +#endif /* AVCODEC_AVCODEC_H */ diff --git a/libavcodec/bit_depth_template.c b/libavcodec/bit_depth_template.c new file mode 100644 index 0000000..9f067c1 --- /dev/null +++ b/libavcodec/bit_depth_template.c @@ -0,0 +1,98 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mathops.h" +#include "rnd_avg.h" +#include "libavutil/intreadwrite.h" + +#ifndef BIT_DEPTH +#define BIT_DEPTH 8 +#endif + +#ifdef AVCODEC_BIT_DEPTH_TEMPLATE_C +# undef pixel +# undef pixel2 +# undef pixel4 +# undef dctcoef +# undef INIT_CLIP +# undef no_rnd_avg_pixel4 +# undef rnd_avg_pixel4 +# undef AV_RN2P +# undef AV_RN4P +# undef AV_RN4PA +# undef AV_WN2P +# undef AV_WN4P +# undef AV_WN4PA +# undef CLIP +# undef FUNC +# undef FUNCC +# undef av_clip_pixel +# undef PIXEL_SPLAT_X4 +#else +# define AVCODEC_BIT_DEPTH_TEMPLATE_C +#endif + +#if defined(USE_VAR_BIT_DEPTH) || BIT_DEPTH > 8 +# define pixel uint16_t +# define pixel2 uint32_t +# define pixel4 uint64_t +# define dctcoef int32_t + +# define INIT_CLIP +# define no_rnd_avg_pixel4 no_rnd_avg64 +# define rnd_avg_pixel4 rnd_avg64 +# define AV_RN2P AV_RN32 +# define AV_RN4P AV_RN64 +# define AV_RN4PA AV_RN64A +# define AV_WN2P AV_WN32 +# define AV_WN4P AV_WN64 +# define AV_WN4PA AV_WN64A +# define PIXEL_SPLAT_X4(x) ((x)*0x0001000100010001ULL) + +# define av_clip_pixel(a) av_clip_uintp2(a, BIT_DEPTH) +# define CLIP(a) av_clip_uintp2(a, BIT_DEPTH) +#else +# define pixel uint8_t +# define pixel2 uint16_t +# define pixel4 uint32_t +# define dctcoef int16_t + +# define INIT_CLIP +# define no_rnd_avg_pixel4 no_rnd_avg32 +# define rnd_avg_pixel4 rnd_avg32 +# define AV_RN2P AV_RN16 +# define AV_RN4P AV_RN32 +# define AV_RN4PA AV_RN32A +# define AV_WN2P AV_WN16 +# define AV_WN4P AV_WN32 +# define AV_WN4PA AV_WN32A +# define PIXEL_SPLAT_X4(x) ((x)*0x01010101U) + +# define av_clip_pixel(a) av_clip_uint8(a) +# define CLIP(a) av_clip_uint8(a) +#endif + +#define FUNC3(a, b, c) a ## _ ## b ## c +#define FUNC2(a, b, c) FUNC3(a, b, c) +#ifdef USE_VAR_BIT_DEPTH +#define FUNC(a) FUNC2(a, var,) +#define FUNCC(a) FUNC2(a, var, _c) +#else +#define FUNC(a) FUNC2(a, BIT_DEPTH,) +#define FUNCC(a) FUNC2(a, BIT_DEPTH, _c) +#endif diff --git a/libavcodec/bswapdsp.h b/libavcodec/bswapdsp.h new file mode 100644 index 0000000..f167d77 --- /dev/null +++ b/libavcodec/bswapdsp.h @@ -0,0 +1,32 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BSWAP_BUF_H +#define AVCODEC_BSWAP_BUF_H + +#include + +typedef struct BswapDSPContext { + void (*bswap_buf)(uint32_t *dst, const uint32_t *src, int w); + void (*bswap16_buf)(uint16_t *dst, const uint16_t *src, int len); +} BswapDSPContext; + +void ff_bswapdsp_init(BswapDSPContext *c); +void ff_bswapdsp_init_x86(BswapDSPContext *c); + +#endif /* AVCODEC_BSWAP_BUF_H */ diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h new file mode 100644 index 0000000..c2cb601 --- /dev/null +++ b/libavcodec/bytestream.h @@ -0,0 +1,374 @@ +/* + * Bytestream functions + * copyright (c) 2006 Baptiste Coudurier + * Copyright (c) 2012 Aneesh Dogra (lionaneesh) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BYTESTREAM_H +#define AVCODEC_BYTESTREAM_H + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" + +typedef struct GetByteContext { + const uint8_t *buffer, *buffer_end, *buffer_start; +} GetByteContext; + +typedef struct PutByteContext { + uint8_t *buffer, *buffer_end, *buffer_start; + int eof; +} PutByteContext; + +#define DEF(type, name, bytes, read, write) \ +static av_always_inline type bytestream_get_ ## name(const uint8_t **b) \ +{ \ + (*b) += bytes; \ + return read(*b - bytes); \ +} \ +static av_always_inline void bytestream_put_ ## name(uint8_t **b, \ + const type value) \ +{ \ + write(*b, value); \ + (*b) += bytes; \ +} \ +static av_always_inline void bytestream2_put_ ## name ## u(PutByteContext *p, \ + const type value) \ +{ \ + bytestream_put_ ## name(&p->buffer, value); \ +} \ +static av_always_inline void bytestream2_put_ ## name(PutByteContext *p, \ + const type value) \ +{ \ + if (!p->eof && (p->buffer_end - p->buffer >= bytes)) { \ + write(p->buffer, value); \ + p->buffer += bytes; \ + } else \ + p->eof = 1; \ +} \ +static av_always_inline type bytestream2_get_ ## name ## u(GetByteContext *g) \ +{ \ + return bytestream_get_ ## name(&g->buffer); \ +} \ +static av_always_inline type bytestream2_get_ ## name(GetByteContext *g) \ +{ \ + if (g->buffer_end - g->buffer < bytes) \ + return 0; \ + return bytestream2_get_ ## name ## u(g); \ +} \ +static av_always_inline type bytestream2_peek_ ## name(GetByteContext *g) \ +{ \ + if (g->buffer_end - g->buffer < bytes) \ + return 0; \ + return read(g->buffer); \ +} + +DEF(uint64_t, le64, 8, AV_RL64, AV_WL64) +DEF(unsigned int, le32, 4, AV_RL32, AV_WL32) +DEF(unsigned int, le24, 3, AV_RL24, AV_WL24) +DEF(unsigned int, le16, 2, AV_RL16, AV_WL16) +DEF(uint64_t, be64, 8, AV_RB64, AV_WB64) +DEF(unsigned int, be32, 4, AV_RB32, AV_WB32) +DEF(unsigned int, be24, 3, AV_RB24, AV_WB24) +DEF(unsigned int, be16, 2, AV_RB16, AV_WB16) +DEF(unsigned int, byte, 1, AV_RB8 , AV_WB8) + +#if HAVE_BIGENDIAN +# define bytestream2_get_ne16 bytestream2_get_be16 +# define bytestream2_get_ne24 bytestream2_get_be24 +# define bytestream2_get_ne32 bytestream2_get_be32 +# define bytestream2_get_ne64 bytestream2_get_be64 +# define bytestream2_get_ne16u bytestream2_get_be16u +# define bytestream2_get_ne24u bytestream2_get_be24u +# define bytestream2_get_ne32u bytestream2_get_be32u +# define bytestream2_get_ne64u bytestream2_get_be64u +# define bytestream2_put_ne16 bytestream2_put_be16 +# define bytestream2_put_ne24 bytestream2_put_be24 +# define bytestream2_put_ne32 bytestream2_put_be32 +# define bytestream2_put_ne64 bytestream2_put_be64 +# define bytestream2_peek_ne16 bytestream2_peek_be16 +# define bytestream2_peek_ne24 bytestream2_peek_be24 +# define bytestream2_peek_ne32 bytestream2_peek_be32 +# define bytestream2_peek_ne64 bytestream2_peek_be64 +#else +# define bytestream2_get_ne16 bytestream2_get_le16 +# define bytestream2_get_ne24 bytestream2_get_le24 +# define bytestream2_get_ne32 bytestream2_get_le32 +# define bytestream2_get_ne64 bytestream2_get_le64 +# define bytestream2_get_ne16u bytestream2_get_le16u +# define bytestream2_get_ne24u bytestream2_get_le24u +# define bytestream2_get_ne32u bytestream2_get_le32u +# define bytestream2_get_ne64u bytestream2_get_le64u +# define bytestream2_put_ne16 bytestream2_put_le16 +# define bytestream2_put_ne24 bytestream2_put_le24 +# define bytestream2_put_ne32 bytestream2_put_le32 +# define bytestream2_put_ne64 bytestream2_put_le64 +# define bytestream2_peek_ne16 bytestream2_peek_le16 +# define bytestream2_peek_ne24 bytestream2_peek_le24 +# define bytestream2_peek_ne32 bytestream2_peek_le32 +# define bytestream2_peek_ne64 bytestream2_peek_le64 +#endif + +static av_always_inline void bytestream2_init(GetByteContext *g, + const uint8_t *buf, + int buf_size) +{ + av_assert0(buf_size >= 0); + g->buffer = buf; + g->buffer_start = buf; + g->buffer_end = buf + buf_size; +} + +static av_always_inline void bytestream2_init_writer(PutByteContext *p, + uint8_t *buf, + int buf_size) +{ + av_assert0(buf_size >= 0); + p->buffer = buf; + p->buffer_start = buf; + p->buffer_end = buf + buf_size; + p->eof = 0; +} + +static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g) +{ + return g->buffer_end - g->buffer; +} + +static av_always_inline unsigned int bytestream2_get_bytes_left_p(PutByteContext *p) +{ + return p->buffer_end - p->buffer; +} + +static av_always_inline void bytestream2_skip(GetByteContext *g, + unsigned int size) +{ + g->buffer += FFMIN(g->buffer_end - g->buffer, size); +} + +static av_always_inline void bytestream2_skipu(GetByteContext *g, + unsigned int size) +{ + g->buffer += size; +} + +static av_always_inline void bytestream2_skip_p(PutByteContext *p, + unsigned int size) +{ + int size2; + if (p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + p->buffer += size2; +} + +static av_always_inline int bytestream2_tell(GetByteContext *g) +{ + return (int)(g->buffer - g->buffer_start); +} + +static av_always_inline int bytestream2_tell_p(PutByteContext *p) +{ + return (int)(p->buffer - p->buffer_start); +} + +static av_always_inline int bytestream2_size(GetByteContext *g) +{ + return (int)(g->buffer_end - g->buffer_start); +} + +static av_always_inline int bytestream2_size_p(PutByteContext *p) +{ + return (int)(p->buffer_end - p->buffer_start); +} + +static av_always_inline int bytestream2_seek(GetByteContext *g, + int offset, + int whence) +{ + switch (whence) { + case SEEK_CUR: + offset = av_clip(offset, -(g->buffer - g->buffer_start), + g->buffer_end - g->buffer); + g->buffer += offset; + break; + case SEEK_END: + offset = av_clip(offset, -(g->buffer_end - g->buffer_start), 0); + g->buffer = g->buffer_end + offset; + break; + case SEEK_SET: + offset = av_clip(offset, 0, g->buffer_end - g->buffer_start); + g->buffer = g->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell(g); +} + +static av_always_inline int bytestream2_seek_p(PutByteContext *p, + int offset, + int whence) +{ + p->eof = 0; + switch (whence) { + case SEEK_CUR: + if (p->buffer_end - p->buffer < offset) + p->eof = 1; + offset = av_clip(offset, -(p->buffer - p->buffer_start), + p->buffer_end - p->buffer); + p->buffer += offset; + break; + case SEEK_END: + if (offset > 0) + p->eof = 1; + offset = av_clip(offset, -(p->buffer_end - p->buffer_start), 0); + p->buffer = p->buffer_end + offset; + break; + case SEEK_SET: + if (p->buffer_end - p->buffer_start < offset) + p->eof = 1; + offset = av_clip(offset, 0, p->buffer_end - p->buffer_start); + p->buffer = p->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell_p(p); +} + +static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, + uint8_t *dst, + unsigned int size) +{ + int size2 = FFMIN(g->buffer_end - g->buffer, size); + memcpy(dst, g->buffer, size2); + g->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, + uint8_t *dst, + unsigned int size) +{ + memcpy(dst, g->buffer, size); + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_put_buffer(PutByteContext *p, + const uint8_t *src, + unsigned int size) +{ + int size2; + if (p->eof) + return 0; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + memcpy(p->buffer, src, size2); + p->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_put_bufferu(PutByteContext *p, + const uint8_t *src, + unsigned int size) +{ + memcpy(p->buffer, src, size); + p->buffer += size; + return size; +} + +static av_always_inline void bytestream2_set_buffer(PutByteContext *p, + const uint8_t c, + unsigned int size) +{ + int size2; + if (p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + memset(p->buffer, c, size2); + p->buffer += size2; +} + +static av_always_inline void bytestream2_set_bufferu(PutByteContext *p, + const uint8_t c, + unsigned int size) +{ + memset(p->buffer, c, size); + p->buffer += size; +} + +static av_always_inline unsigned int bytestream2_get_eof(PutByteContext *p) +{ + return p->eof; +} + +static av_always_inline unsigned int bytestream2_copy_bufferu(PutByteContext *p, + GetByteContext *g, + unsigned int size) +{ + memcpy(p->buffer, g->buffer, size); + p->buffer += size; + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_copy_buffer(PutByteContext *p, + GetByteContext *g, + unsigned int size) +{ + int size2; + + if (p->eof) + return 0; + size = FFMIN(g->buffer_end - g->buffer, size); + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + + return bytestream2_copy_bufferu(p, g, size2); +} + +static av_always_inline unsigned int bytestream_get_buffer(const uint8_t **b, + uint8_t *dst, + unsigned int size) +{ + memcpy(dst, *b, size); + (*b) += size; + return size; +} + +static av_always_inline void bytestream_put_buffer(uint8_t **b, + const uint8_t *src, + unsigned int size) +{ + memcpy(*b, src, size); + (*b) += size; +} + +#endif /* AVCODEC_BYTESTREAM_H */ diff --git a/libavcodec/cabac.c b/libavcodec/cabac.c new file mode 100644 index 0000000..81a75dd --- /dev/null +++ b/libavcodec/cabac.c @@ -0,0 +1,227 @@ +/* + * H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Context Adaptive Binary Arithmetic Coder. + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/timer.h" +#include "get_bits.h" +#include "cabac.h" +#include "cabac_functions.h" + +#include "cabac_tablegen.h" + +/** + * + * @param buf_size size of buf in bits + */ +void ff_init_cabac_encoder(CABACContext *c, uint8_t *buf, int buf_size){ + init_put_bits(&c->pb, buf, buf_size); + + c->low= 0; + c->range= 0x1FE; + c->outstanding_count= 0; + c->pb.bit_left++; //avoids firstBitFlag +} + +/** + * + * @param buf_size size of buf in bits + */ +void ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size){ + c->bytestream_start= + c->bytestream= buf; + c->bytestream_end= buf + buf_size; + +#if CABAC_BITS == 16 + c->low = (*c->bytestream++)<<18; + c->low+= (*c->bytestream++)<<10; +#else + c->low = (*c->bytestream++)<<10; +#endif + c->low+= ((*c->bytestream++)<<2) + 2; + c->range= 0x1FE; +} + +void ff_init_cabac_states(void) +{ + static int initialized = 0; + + if (initialized) + return; + + cabac_tableinit(); + + initialized = 1; +} + +#ifdef TEST +#define SIZE 10240 + +#include "libavutil/lfg.h" +#include "avcodec.h" + +static inline void put_cabac_bit(CABACContext *c, int b){ + put_bits(&c->pb, 1, b); + for(;c->outstanding_count; c->outstanding_count--){ + put_bits(&c->pb, 1, 1-b); + } +} + +static inline void renorm_cabac_encoder(CABACContext *c){ + while(c->range < 0x100){ + //FIXME optimize + if(c->low<0x100){ + put_cabac_bit(c, 0); + }else if(c->low<0x200){ + c->outstanding_count++; + c->low -= 0x100; + }else{ + put_cabac_bit(c, 1); + c->low -= 0x200; + } + + c->range+= c->range; + c->low += c->low; + } +} + +static void put_cabac(CABACContext *c, uint8_t * const state, int bit){ + int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + *state]; + + if(bit == ((*state)&1)){ + c->range -= RangeLPS; + *state = ff_h264_mlps_state[128 + *state]; + }else{ + c->low += c->range - RangeLPS; + c->range = RangeLPS; + *state= ff_h264_mlps_state[127 - *state]; + } + + renorm_cabac_encoder(c); +} + +/** + * @param bit 0 -> write zero bit, !=0 write one bit + */ +static void put_cabac_bypass(CABACContext *c, int bit){ + c->low += c->low; + + if(bit){ + c->low += c->range; + } +//FIXME optimize + if(c->low<0x200){ + put_cabac_bit(c, 0); + }else if(c->low<0x400){ + c->outstanding_count++; + c->low -= 0x200; + }else{ + put_cabac_bit(c, 1); + c->low -= 0x400; + } +} + +/** + * + * @return the number of bytes written + */ +static int put_cabac_terminate(CABACContext *c, int bit){ + c->range -= 2; + + if(!bit){ + renorm_cabac_encoder(c); + }else{ + c->low += c->range; + c->range= 2; + + renorm_cabac_encoder(c); + + av_assert0(c->low <= 0x1FF); + put_cabac_bit(c, c->low>>9); + put_bits(&c->pb, 2, ((c->low>>7)&3)|1); + + flush_put_bits(&c->pb); //FIXME FIXME FIXME XXX wrong + } + + return (put_bits_count(&c->pb)+7)>>3; +} + +int main(void){ + CABACContext c; + uint8_t b[9*SIZE]; + uint8_t r[9*SIZE]; + int i; + uint8_t state[10]= {0}; + AVLFG prng; + + av_lfg_init(&prng, 1); + ff_init_cabac_encoder(&c, b, SIZE); + ff_init_cabac_states(); + + for(i=0; i>8)&1; + } + + for(i=0; i + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Context Adaptive Binary Arithmetic Coder. + */ + +#ifndef AVCODEC_CABAC_H +#define AVCODEC_CABAC_H + +#include + +#include "put_bits.h" + +#if CONFIG_HARDCODED_TABLES +#define CABAC_TABLE_CONST const +#else +#define CABAC_TABLE_CONST +#endif +extern CABAC_TABLE_CONST uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63]; +#define H264_NORM_SHIFT_OFFSET 0 +#define H264_LPS_RANGE_OFFSET 512 +#define H264_MLPS_STATE_OFFSET 1024 +#define H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET 1280 + +#define CABAC_BITS 16 +#define CABAC_MASK ((1< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Context Adaptive Binary Arithmetic Coder inline functions + */ + +#ifndef AVCODEC_CABAC_FUNCTIONS_H +#define AVCODEC_CABAC_FUNCTIONS_H + +#include + +#include "cabac.h" +#include "config.h" + +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +#if ARCH_AARCH64 +# include "aarch64/cabac.h" +#endif +#if ARCH_ARM +# include "arm/cabac.h" +#endif +#if ARCH_X86 +# include "x86/cabac.h" +#endif + +static CABAC_TABLE_CONST uint8_t * const ff_h264_norm_shift = ff_h264_cabac_tables + H264_NORM_SHIFT_OFFSET; +static CABAC_TABLE_CONST uint8_t * const ff_h264_lps_range = ff_h264_cabac_tables + H264_LPS_RANGE_OFFSET; +static CABAC_TABLE_CONST uint8_t * const ff_h264_mlps_state = ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET; +static CABAC_TABLE_CONST uint8_t * const ff_h264_last_coeff_flag_offset_8x8 = ff_h264_cabac_tables + H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET; + +static void refill(CABACContext *c){ +#if CABAC_BITS == 16 + c->low+= (c->bytestream[0]<<9) + (c->bytestream[1]<<1); +#else + c->low+= c->bytestream[0]<<1; +#endif + c->low -= CABAC_MASK; +#if !UNCHECKED_BITSTREAM_READER + if (c->bytestream < c->bytestream_end) +#endif + c->bytestream += CABAC_BITS / 8; +} + +static inline void renorm_cabac_decoder_once(CABACContext *c){ + int shift= (uint32_t)(c->range - 0x100)>>31; + c->range<<= shift; + c->low <<= shift; + if(!(c->low & CABAC_MASK)) + refill(c); +} + +#ifndef get_cabac_inline +static void refill2(CABACContext *c){ + int i, x; + + x= c->low ^ (c->low-1); + i= 7 - ff_h264_norm_shift[x>>(CABAC_BITS-1)]; + + x= -CABAC_MASK; + +#if CABAC_BITS == 16 + x+= (c->bytestream[0]<<9) + (c->bytestream[1]<<1); +#else + x+= c->bytestream[0]<<1; +#endif + + c->low += x<bytestream < c->bytestream_end) +#endif + c->bytestream += CABAC_BITS/8; +} + +static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const state){ + int s = *state; + int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + s]; + int bit, lps_mask; + + c->range -= RangeLPS; + lps_mask= ((c->range<<(CABAC_BITS+1)) - c->low)>>31; + + c->low -= (c->range<<(CABAC_BITS+1)) & lps_mask; + c->range += (RangeLPS - c->range) & lps_mask; + + s^=lps_mask; + *state= (ff_h264_mlps_state+128)[s]; + bit= s&1; + + lps_mask= ff_h264_norm_shift[c->range]; + c->range<<= lps_mask; + c->low <<= lps_mask; + if(!(c->low & CABAC_MASK)) + refill2(c); + return bit; +} +#endif + +static int av_noinline av_unused get_cabac_noinline(CABACContext *c, uint8_t * const state){ + return get_cabac_inline(c,state); +} + +static int av_unused get_cabac(CABACContext *c, uint8_t * const state){ + return get_cabac_inline(c,state); +} + +#ifndef get_cabac_bypass +static int av_unused get_cabac_bypass(CABACContext *c){ + int range; + c->low += c->low; + + if(!(c->low & CABAC_MASK)) + refill(c); + + range= c->range<<(CABAC_BITS+1); + if(c->low < range){ + return 0; + }else{ + c->low -= range; + return 1; + } +} +#endif + +#ifndef get_cabac_bypass_sign +static av_always_inline int get_cabac_bypass_sign(CABACContext *c, int val){ + int range, mask; + c->low += c->low; + + if(!(c->low & CABAC_MASK)) + refill(c); + + range= c->range<<(CABAC_BITS+1); + c->low -= range; + mask= c->low >> 31; + range &= mask; + c->low += range; + return (val^mask)-mask; +} +#endif + +/** + * + * @return the number of bytes read or 0 if no end + */ +static int av_unused get_cabac_terminate(CABACContext *c){ + c->range -= 2; + if(c->low < c->range<<(CABAC_BITS+1)){ + renorm_cabac_decoder_once(c); + return 0; + }else{ + return c->bytestream - c->bytestream_start; + } +} + +/** + * Skip @p n bytes and reset the decoder. + * @return the address of the first skipped byte or NULL if there's less than @p n bytes left + */ +static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) { + const uint8_t *ptr = c->bytestream; + + if (c->low & 0x1) + ptr--; +#if CABAC_BITS == 16 + if (c->low & 0x1FF) + ptr--; +#endif + if ((int) (c->bytestream_end - ptr) < n) + return NULL; + ff_init_cabac_decoder(c, ptr + n, c->bytestream_end - ptr - n); + + return ptr; +} + +#endif /* AVCODEC_CABAC_FUNCTIONS_H */ diff --git a/libavcodec/cabac_tablegen.h b/libavcodec/cabac_tablegen.h new file mode 100644 index 0000000..a637912 --- /dev/null +++ b/libavcodec/cabac_tablegen.h @@ -0,0 +1,108 @@ +/* + * Header file for hardcoded CABAC table + * + * Copyright (c) 2014 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CABAC_TABLEGEN_H +#define AVCODEC_CABAC_TABLEGEN_H + +#if CONFIG_HARDCODED_TABLES +#define cabac_tableinit() +#include "libavcodec/cabac_tables.h" +#else +uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63]; + +static const uint8_t lps_range[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 uint8_t mps_state[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 uint8_t lps_state[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 uint8_t last_coeff_flag_offset_8x8[63] = { + 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 +}; + +static av_cold void cabac_tableinit(void) +{ + int i, j; + for (i = 0; i < 512; i++) + ff_h264_norm_shift[i] = i ? 8 - av_log2(i) : 9; + + for(i=0; i<64; i++){ + for(j=0; j<4; j++){ //FIXME check if this is worth the 1 shift we save + ff_h264_lps_range[j*2*64+2*i+0]= + ff_h264_lps_range[j*2*64+2*i+1]= lps_range[i][j]; + } + ff_h264_mlps_state[128 + 2 * i + 0] = 2 * mps_state[i] + 0; + ff_h264_mlps_state[128 + 2 * i + 1] = 2 * mps_state[i] + 1; + + if( i ){ + ff_h264_mlps_state[128-2*i-1]= 2*lps_state[i]+0; + ff_h264_mlps_state[128-2*i-2]= 2*lps_state[i]+1; + }else{ + ff_h264_mlps_state[128-2*i-1]= 1; + ff_h264_mlps_state[128-2*i-2]= 0; + } + } + for(i=0; i< 63; i++){ + ff_h264_last_coeff_flag_offset_8x8[i] = last_coeff_flag_offset_8x8[i]; + } +} +#endif /* CONFIG_HARDCODED_TABLES */ + +#endif /* AVCODEC_CABAC_TABLEGEN_H */ diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h new file mode 100644 index 0000000..01ade4c --- /dev/null +++ b/libavcodec/get_bits.h @@ -0,0 +1,707 @@ +/* + * copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream reader API header. + */ + +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/avassert.h" +#include "mathops.h" + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bit (FIXME 64bit). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#ifdef LONG_BITSTREAM_READER +# define MIN_CACHE_BITS 32 +#else +# define MIN_CACHE_BITS 25 +#endif + +#define OPEN_READER_NOSIZE(name, gb) \ + unsigned int name ## _index = (gb)->index; \ + unsigned int av_unused name ## _cache + +#if UNCHECKED_BITSTREAM_READER +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) 1 +#else +#define OPEN_READER(name, gb) \ + OPEN_READER_NOSIZE(name, gb); \ + unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 + +#define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 +#endif + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +# ifdef LONG_BITSTREAM_READER + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7)) + +#else + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) + +#endif + + +#ifdef BITSTREAM_READER_LE + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#else + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#endif + +#if UNCHECKED_BITSTREAM_READER +# define SKIP_COUNTER(name, gb, num) name ## _index += (num) +#else +# define SKIP_COUNTER(name, gb, num) \ + name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num)) +#endif + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) + +static inline int get_bits_count(const GetBitContext *s) +{ + return s->index; +} + +static inline void skip_bits_long(GetBitContext *s, int n) +{ +#if UNCHECKED_BITSTREAM_READER + s->index += n; +#else + s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); +#endif +} + +/** + * read mpeg1 dc style vlc (sign bit + mantissa with no MSB). + * if MSB not set it is negative + * @param n length in bits + */ +static inline int get_xbits(GetBitContext *s, int n) +{ + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + cache = GET_CACHE(re, s); + sign = ~cache >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +} + +static inline int get_sbits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +#ifdef CONFIG_SMALL +unsigned int get_bits(GetBitContext *s, int n); +unsigned int show_bits(GetBitContext *s, int n); +void skip_bits(GetBitContext *s, int n); +unsigned int get_bits1(GetBitContext *s); +unsigned int show_bits1(GetBitContext *s); +void skip_bits1(GetBitContext *s); +unsigned int get_bits_long(GetBitContext *s, int n); + +#else +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Show 1-25 bits. + */ +static inline unsigned int show_bits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER_NOSIZE(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + return tmp; +} + +static inline void skip_bits(GetBitContext *s, int n) +{ + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +static inline unsigned int get_bits1(GetBitContext *s) +{ + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if (s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +} + +static inline unsigned int show_bits1(GetBitContext *s) +{ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s) +{ + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +static inline unsigned int get_bits_long(GetBitContext *s, int n) +{ + if (!n) { + return 0; + } else if (n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +} +#endif /* !CONFIG_SMALL */ + +static inline unsigned int get_bits_le(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Read 0-64 bits. + */ +static inline uint64_t get_bits64(GetBitContext *s, int n) +{ + if (n <= 32) { + return get_bits_long(s, n); + } else { +#ifdef BITSTREAM_READER_LE + uint64_t ret = get_bits_long(s, 32); + return ret | (uint64_t) get_bits_long(s, n - 32) << 32; +#else + uint64_t ret = (uint64_t) get_bits_long(s, n - 32) << 32; + return ret | get_bits_long(s, 32); +#endif + } +} + +/** + * Read 0-32 bits as a signed integer. + */ +static inline int get_sbits_long(GetBitContext *s, int n) +{ + return sign_extend(get_bits_long(s, n), n); +} + +/** + * Show 0-32 bits. + */ +static inline unsigned int show_bits_long(GetBitContext *s, int n) +{ + if (n <= MIN_CACHE_BITS) { + return show_bits(s, n); + } else { + GetBitContext gb = *s; + return get_bits_long(&gb, n); + } +} + +static inline int check_marker(GetBitContext *s, const char *msg) +{ + int bit = get_bits1(s); + if (!bit) + av_log(NULL, AV_LOG_INFO, "Marker bit missing %s\n", msg); + + return bit; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be FF_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ + int buffer_size; + int ret = 0; + + if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be FF_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) +{ + int n = -get_bits_count(s) & 7; + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +#define init_vlc(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_init_vlc_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); +void ff_free_vlc(VLC *vlc); + +#define INIT_VLC_LE 2 +#define INIT_VLC_USE_NEW_STATIC 4 + +#define INIT_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + init_vlc(vlc, bits, a, b, c, d, e, f, g, INIT_VLC_USE_NEW_STATIC); \ + } while (0) + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + +#define GET_RL_VLC_INTERNAL(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + level = table[index].level; \ + n = table[index].len; \ + \ + if (max_depth > 1 && n < 0) { \ + SKIP_BITS(name, gb, bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + } \ + run = table[index].run; \ + SKIP_BITS(name, gb, n); \ + } while (0) + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +} + +static inline int decode012(GetBitContext *gb) +{ + int n; + n = get_bits1(gb); + if (n == 0) + return 0; + else + return get_bits1(gb) + 1; +} + +static inline int decode210(GetBitContext *gb) +{ + if (get_bits1(gb)) + return 0; + else + return 2 - get_bits1(gb); +} + +static inline int get_bits_left(GetBitContext *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +static inline int skip_1stop_8data_bits(GetBitContext *gb) +{ + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + while (get_bits1(gb)) { + skip_bits(gb, 8); + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + } + + return 0; +} + +//#define TRACE + +#ifdef TRACE +static inline void print_bin(int bits, int n) +{ + int i; + + for (i = n - 1; i >= 0; i--) + av_log(NULL, AV_LOG_DEBUG, "%d", (bits >> i) & 1); + for (i = n; i < 24; i++) + av_log(NULL, AV_LOG_DEBUG, " "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, const char *file, + const char *func, int line) +{ + int r = get_bits(s, n); + + print_bin(r, n); + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d bit @%5d in %s %s:%d\n", + r, n, r, get_bits_count(s) - n, file, func, line); + + return r; +} + +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth, const char *file, + const char *func, int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int r = get_vlc2(s, table, bits, max_depth); + int len = get_bits_count(s) - pos; + int bits2 = show >> (24 - len); + + print_bin(bits2, len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d vlc @%5d in %s %s:%d\n", + bits2, len, r, pos, file, func, line); + + return r; +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int show = SHOW_UBITS(name, gb, 24); \ + int len; \ + int pos = name ## _index; \ + \ + GET_RL_VLC_INTERNAL(level, run, name, gb, table, bits,max_depth, need_update); \ + \ + len = name ## _index - pos + 1; \ + show = show >> (24 - len); \ + \ + print_bin(show, len); \ + \ + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d/%-3d rlv @%5d in %s %s:%d\n",\ + show, len, run-1, level, pos, __FILE__, __PRETTY_FUNCTION__, __LINE__);\ + } while (0) \ + + +static inline int get_xbits_trace(GetBitContext *s, int n, const char *file, + const char *func, int line) +{ + int show = show_bits(s, n); + int r = get_xbits(s, n); + + print_bin(show, n); + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d xbt @%5d in %s %s:%d\n", + show, n, r, get_bits_count(s) - n, file, func, line); + + return r; +} + +#define get_bits(s, n) get_bits_trace(s , n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf(p, ...) av_log(p, AV_LOG_DEBUG, __VA_ARGS__) + +#else //TRACE +#define tprintf(p, ...) { } +#define GET_RL_VLC GET_RL_VLC_INTERNAL +#endif + +#endif /* AVCODEC_GET_BITS_H */ diff --git a/libavcodec/golomb.c b/libavcodec/golomb.c new file mode 100644 index 0000000..de7d73f --- /dev/null +++ b/libavcodec/golomb.c @@ -0,0 +1,285 @@ +/* + * exp golomb vlc stuff + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief + * exp golomb vlc stuff + * @author Michael Niedermayer + */ + +#include "libavutil/common.h" + +#ifdef CONFIG_SMALL + +#include "golomb.h" + +unsigned int get_bits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Show 1-25 bits. + */ +unsigned int show_bits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER_NOSIZE(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + return tmp; +} + +void skip_bits(GetBitContext *s, int n) +{ + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +unsigned int get_bits1(GetBitContext *s) +{ + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if (s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +} + +unsigned int show_bits1(GetBitContext *s) +{ + return show_bits(s, 1); +} + +void skip_bits1(GetBitContext *s) +{ + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +unsigned int get_bits_long(GetBitContext *s, int n) +{ + if (!n) { + return 0; + } else if (n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +} + +unsigned get_ue_golomb_long(GetBitContext *gb) +{ + unsigned buf, log; + + buf = show_bits_long(gb, 32); + log = 31 - av_log2(buf); + skip_bits_long(gb, log); + + return get_bits_long(gb, log + 1) - 1; +} + +int get_se_golomb_long(GetBitContext *gb) +{ + unsigned int buf = get_ue_golomb_long(gb); + + if (buf & 1) + buf = (buf + 1) >> 1; + else + buf = -(buf >> 1); + + return buf; +} + +#else + +const uint8_t ff_golomb_vlc_len[512]={ +19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +const uint8_t ff_ue_golomb_vlc_code[512]={ +32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 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, 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, 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 +}; + +const int8_t ff_se_golomb_vlc_code[512]={ + 17, 17, 17, 17, 17, 17, 17, 17, 16, 17, 17, 17, 17, 17, 17, 17, 8, -8, 9, -9, 10,-10, 11,-11, 12,-12, 13,-13, 14,-14, 15,-15, + 4, 4, 4, 4, -4, -4, -4, -4, 5, 5, 5, 5, -5, -5, -5, -5, 6, 6, 6, 6, -6, -6, -6, -6, 7, 7, 7, 7, -7, -7, -7, -7, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, 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, + 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, 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, +}; + +const uint8_t ff_ue_golomb_len[256]={ + 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17, +}; + +const uint8_t ff_interleaved_golomb_vlc_len[256]={ +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +const uint8_t ff_interleaved_ue_golomb_vlc_code[256]={ + 15,16,7, 7, 17,18,8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 19,20,9, 9, 21,22,10,10,4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23,24,11,11,25,26,12,12,5, 5, 5, 5, 5, 5, 5, 5, + 27,28,13,13,29,30,14,14,6, 6, 6, 6, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 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, 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, +}; + +const int8_t ff_interleaved_se_golomb_vlc_code[256]={ + 8, -8, 4, 4, 9, -9, -4, -4, 2, 2, 2, 2, 2, 2, 2, 2, + 10,-10, 5, 5, 11,-11, -5, -5, -2, -2, -2, -2, -2, -2, -2, -2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 12,-12, 6, 6, 13,-13, -6, -6, 3, 3, 3, 3, 3, 3, 3, 3, + 14,-14, 7, 7, 15,-15, -7, -7, -3, -3, -3, -3, -3, -3, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -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, 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, +}; + +const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]={ +0, 1, 0, 0, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +4, 5, 2, 2, 6, 7, 3, 3, 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, +8, 9, 4, 4, 10,11,5, 5, 2, 2, 2, 2, 2, 2, 2, 2, +12,13,6, 6, 14,15,7, 7, 3, 3, 3, 3, 3, 3, 3, 3, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 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, 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,}; + +#endif diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h new file mode 100644 index 0000000..5be3c26 --- /dev/null +++ b/libavcodec/golomb.h @@ -0,0 +1,623 @@ +/* + * exp golomb vlc stuff + * Copyright (c) 2003 Michael Niedermayer + * Copyright (c) 2004 Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief + * exp golomb vlc stuff + * @author Michael Niedermayer and Alex Beregszaszi + */ + +#ifndef AVCODEC_GOLOMB_H +#define AVCODEC_GOLOMB_H + +#include + +#include "get_bits.h" +#include "put_bits.h" + +#define INVALID_VLC 0x80000000 + +extern const uint8_t ff_golomb_vlc_len[512]; +extern const uint8_t ff_ue_golomb_vlc_code[512]; +extern const int8_t ff_se_golomb_vlc_code[512]; +extern const uint8_t ff_ue_golomb_len[256]; + +extern const uint8_t ff_interleaved_golomb_vlc_len[256]; +extern const uint8_t ff_interleaved_ue_golomb_vlc_code[256]; +extern const int8_t ff_interleaved_se_golomb_vlc_code[256]; +extern const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]; + +#ifdef CONFIG_SMALL +unsigned get_ue_golomb_long(GetBitContext *gb); + +static inline int get_ue_golomb(GetBitContext *gb) +{ + return get_ue_golomb_long(gb); +} +#else +/** + * Read an unsigned Exp-Golomb code in the range 0 to UINT32_MAX-1. + */ +static inline unsigned get_ue_golomb_long(GetBitContext *gb) +{ + unsigned buf, log; + + buf = show_bits_long(gb, 32); + log = 31 - av_log2(buf); + skip_bits_long(gb, log); + + return get_bits_long(gb, log + 1) - 1; +} + +/** + * read unsigned exp golomb code. + */ +static inline int get_ue_golomb(GetBitContext *gb) +{ + unsigned int buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_ue_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + if (CONFIG_FTRAPV && log < 0) { + av_log(0, AV_LOG_ERROR, "Invalid UE golomb code\n"); + return AVERROR_INVALIDDATA; + } + buf >>= log; + buf--; + + return buf; + } +} +#endif + +/** + * read unsigned exp golomb code, constraint to a max of 31. + * the return value is undefined if the stored value exceeds 31. + */ +static inline int get_ue_golomb_31(GetBitContext *gb) +{ + unsigned int buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_ue_golomb_vlc_code[buf]; +} + +static inline unsigned svq3_get_ue_golomb(GetBitContext *gb) +{ + uint32_t buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_ue_golomb_vlc_code[buf]; + } else { + unsigned ret = 1; + + do { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, + FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); + + if (ff_interleaved_golomb_vlc_len[buf] != 9) { + ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; + ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; + break; + } + ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + } while (ret<0x8000000U && BITS_AVAILABLE(re, gb)); + + CLOSE_READER(re, gb); + return ret - 1; + } +} + +/** + * read unsigned truncated exp golomb code. + */ +static inline int get_te0_golomb(GetBitContext *gb, int range) +{ + av_assert2(range >= 1); + + if (range == 1) + return 0; + else if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +/** + * read unsigned truncated exp golomb code. + */ +static inline int get_te_golomb(GetBitContext *gb, int range) +{ + av_assert2(range >= 1); + + if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +#ifdef CONFIG_SMALL +int get_se_golomb_long(GetBitContext *gb); + +static inline int get_se_golomb(GetBitContext *gb) +{ + return get_se_golomb_long(gb); +} +#else +static inline int get_se_golomb_long(GetBitContext *gb) +{ + unsigned int buf = get_ue_golomb_long(gb); + + if (buf & 1) + buf = (buf + 1) >> 1; + else + buf = -(buf >> 1); + + return buf; +} + +/** + * read signed exp golomb code. + */ +static inline int get_se_golomb(GetBitContext *gb) +{ + unsigned int buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_se_golomb_vlc_code[buf]; + } else { + int log = av_log2(buf); + LAST_SKIP_BITS(re, gb, 31 - log); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= log; + + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + + if (buf & 1) + buf = -(buf >> 1); + else + buf = (buf >> 1); + + return buf; + } +} +#endif + +static inline int svq3_get_se_golomb(GetBitContext *gb) +{ + unsigned int buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_se_golomb_vlc_code[buf]; + } else { + int log; + LAST_SKIP_BITS(re, gb, 8); + UPDATE_CACHE(re, gb); + buf |= 1 | (GET_CACHE(re, gb) >> 8); + + if ((buf & 0xAAAAAAAA) == 0) + return INVALID_VLC; + + for (log = 31; (buf & 0x80000000) == 0; log--) + buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); + + LAST_SKIP_BITS(re, gb, 63 - 2 * log - 8); + CLOSE_READER(re, gb); + + return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; + } +} + +static inline int dirac_get_se_golomb(GetBitContext *gb) +{ + uint32_t ret = svq3_get_ue_golomb(gb); + + if (ret) { + uint32_t buf; + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = SHOW_SBITS(re, gb, 1); + LAST_SKIP_BITS(re, gb, 1); + ret = (ret ^ buf) - buf; + CLOSE_READER(re, gb); + } + + return ret; +} + +/** + * read unsigned golomb rice code (ffv1). + */ +static inline int get_ur_golomb(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned int buf; + int log; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + if (log > 31 - limit) { + buf >>= log - k; + buf += (30 - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + LAST_SKIP_BITS(re, gb, limit); + UPDATE_CACHE(re, gb); + + buf = SHOW_UBITS(re, gb, esc_len); + + LAST_SKIP_BITS(re, gb, esc_len); + CLOSE_READER(re, gb); + + return buf + limit - 1; + } +} + +/** + * read unsigned golomb rice code (jpegls). + */ +static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned int buf; + int log; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) && + 32 - log < limit) { + buf >>= log - k; + buf += (30 - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + int i; + for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { + if (gb->size_in_bits <= re_index) + return -1; + LAST_SKIP_BITS(re, gb, 1); + UPDATE_CACHE(re, gb); + } + SKIP_BITS(re, gb, 1); + + if (i < limit - 1) { + if (k) { + buf = SHOW_UBITS(re, gb, k); + LAST_SKIP_BITS(re, gb, k); + } else { + buf = 0; + } + + CLOSE_READER(re, gb); + return buf + (i << k); + } else if (i == limit - 1) { + buf = SHOW_UBITS(re, gb, esc_len); + LAST_SKIP_BITS(re, gb, esc_len); + CLOSE_READER(re, gb); + + return buf + 1; + } else + return -1; + } +} + +/** + * read signed golomb rice code (ffv1). + */ +static inline int get_sr_golomb(GetBitContext *gb, int k, int limit, + int esc_len) +{ + int v = get_ur_golomb(gb, k, limit, esc_len); + + v++; + if (v & 1) + return v >> 1; + else + return -(v >> 1); + +// return (v>>1) ^ -(v&1); +} + +/** + * read signed golomb rice code (flac). + */ +static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit, + int esc_len) +{ + int v = get_ur_golomb_jpegls(gb, k, limit, esc_len); + return (v >> 1) ^ -(v & 1); +} + +/** + * read unsigned golomb rice code (shorten). + */ +static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k) +{ + return get_ur_golomb_jpegls(gb, k, INT_MAX, 0); +} + +/** + * read signed golomb rice code (shorten). + */ +static inline int get_sr_golomb_shorten(GetBitContext *gb, int k) +{ + int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0); + if (uvar & 1) + return ~(uvar >> 1); + else + return uvar >> 1; +} + +#ifdef TRACE + +static inline int get_ue(GetBitContext *s, const char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_ue_golomb(s); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + print_bin(bits, len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d ue @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +static inline int get_se(GetBitContext *s, const char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_se_golomb(s); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + print_bin(bits, len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d se @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +static inline int get_te(GetBitContext *s, int r, char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_te0_golomb(s, r); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + print_bin(bits, len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d te @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +#define get_ue_golomb(a) get_ue(a, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_se_golomb(a) get_se(a, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_te_golomb(a, r) get_te(a, r, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_te0_golomb(a, r) get_te(a, r, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#endif /* TRACE */ + +/** + * write unsigned exp golomb code. + */ +static inline void set_ue_golomb(PutBitContext *pb, int i) +{ + av_assert2(i >= 0); + +#if 0 + if (i = 0) { + put_bits(pb, 1, 1); + return; + } +#endif + if (i < 256) + put_bits(pb, ff_ue_golomb_len[i], i + 1); + else { + int e = av_log2(i + 1); + put_bits(pb, 2 * e + 1, i + 1); + } +} + +/** + * write truncated unsigned exp golomb code. + */ +static inline void set_te_golomb(PutBitContext *pb, int i, int range) +{ + av_assert2(range >= 1); + av_assert2(i <= range); + + if (range == 2) + put_bits(pb, 1, i ^ 1); + else + set_ue_golomb(pb, i); +} + +/** + * write signed exp golomb code. 16 bits at most. + */ +static inline void set_se_golomb(PutBitContext *pb, int i) +{ +#if 0 + if (i <= 0) + i = -2 * i; + else + i = 2 * i - 1; +#elif 1 + i = 2 * i - 1; + if (i < 0) + i ^= -1; //FIXME check if gcc does the right thing +#else + i = 2 * i - 1; + i ^= (i >> 31); +#endif + set_ue_golomb(pb, i); +} + +/** + * write unsigned golomb rice code (ffv1). + */ +static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, + int esc_len) +{ + int e; + + av_assert2(i >= 0); + + e = i >> k; + if (e < limit) + put_bits(pb, e + k + 1, (1 << k) + (i & ((1 << k) - 1))); + else + put_bits(pb, limit + esc_len, i - limit + 1); +} + +/** + * write unsigned golomb rice code (jpegls). + */ +static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k, + int limit, int esc_len) +{ + int e; + + av_assert2(i >= 0); + + e = (i >> k) + 1; + if (e < limit) { + while (e > 31) { + put_bits(pb, 31, 0); + e -= 31; + } + put_bits(pb, e, 1); + if (k) + put_sbits(pb, k, i); + } else { + while (limit > 31) { + put_bits(pb, 31, 0); + limit -= 31; + } + put_bits(pb, limit, 1); + put_bits(pb, esc_len, i - 1); + } +} + +/** + * write signed golomb rice code (ffv1). + */ +static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit, + int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb(pb, v, k, limit, esc_len); +} + +/** + * write signed golomb rice code (flac). + */ +static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k, + int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb_jpegls(pb, v, k, limit, esc_len); +} + +#endif /* AVCODEC_GOLOMB_H */ diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c new file mode 100644 index 0000000..7030980 --- /dev/null +++ b/libavcodec/hevc.c @@ -0,0 +1,3623 @@ +/* + * HEVC video Decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2012 - 2013 Mickael Raulet + * Copyright (C) 2012 - 2013 Gildas Cocherel + * Copyright (C) 2012 - 2013 Wassim Hamidouche + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/atomic.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/display.h" +#include "libavutil/internal.h" +#include "libavutil/md5.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/stereo3d.h" + +#include "bswapdsp.h" +#include "bytestream.h" +#include "cabac_functions.h" +#include "golomb.h" +#include "hevc.h" + +const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 }; + +/** + * NOTE: Each function hls_foo correspond to the function foo in the + * specification (HLS stands for High Level Syntax). + */ + +/** + * Section 5.7 + */ + +/* free everything allocated by pic_arrays_init() */ +static void pic_arrays_free(HEVCContext *s) +{ + av_freep(&s->sao); + av_freep(&s->deblock); + + av_freep(&s->skip_flag); + av_freep(&s->tab_ct_depth); + + av_freep(&s->tab_ipm); + av_freep(&s->cbf_luma); + av_freep(&s->is_pcm); + + av_freep(&s->qp_y_tab); + av_freep(&s->tab_slice_address); + av_freep(&s->filter_slice_edges); + + av_freep(&s->horizontal_bs); + av_freep(&s->vertical_bs); + + av_freep(&s->sh.entry_point_offset); + av_freep(&s->sh.size); + av_freep(&s->sh.offset); +#ifdef USE_PRED + av_buffer_pool_uninit(&s->tab_mvf_pool); + av_buffer_pool_uninit(&s->rpl_tab_pool); +#endif +} + +/* allocate arrays that depend on frame dimensions */ +static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps) +{ + int log2_min_cb_size = sps->log2_min_cb_size; + int width = sps->width; + int height = sps->height; + int pic_size_in_ctb = ((width >> log2_min_cb_size) + 1) * + ((height >> log2_min_cb_size) + 1); + int ctb_count = sps->ctb_width * sps->ctb_height; + int min_pu_size = sps->min_pu_width * sps->min_pu_height; + + s->bs_width = (width >> 2) + 1; + s->bs_height = (height >> 2) + 1; + + s->sao = av_mallocz_array(ctb_count, sizeof(*s->sao)); + s->deblock = av_mallocz_array(ctb_count, sizeof(*s->deblock)); + if (!s->sao || !s->deblock) + goto fail; + + s->skip_flag = av_malloc(sps->min_cb_height * sps->min_cb_width); + s->tab_ct_depth = av_malloc_array(sps->min_cb_height, sps->min_cb_width); + if (!s->skip_flag || !s->tab_ct_depth) + goto fail; + + s->cbf_luma = av_malloc_array(sps->min_tb_width, sps->min_tb_height); + s->tab_ipm = av_mallocz(min_pu_size); + s->is_pcm = av_malloc((sps->min_pu_width + 1) * (sps->min_pu_height + 1)); + if (!s->tab_ipm || !s->cbf_luma || !s->is_pcm) + goto fail; + + s->filter_slice_edges = av_malloc(ctb_count); + s->tab_slice_address = av_malloc_array(pic_size_in_ctb, + sizeof(*s->tab_slice_address)); + s->qp_y_tab = av_malloc_array(pic_size_in_ctb, + sizeof(*s->qp_y_tab)); + if (!s->qp_y_tab || !s->filter_slice_edges || !s->tab_slice_address) + goto fail; + + s->horizontal_bs = av_mallocz_array(s->bs_width, s->bs_height); + s->vertical_bs = av_mallocz_array(s->bs_width, s->bs_height); + if (!s->horizontal_bs || !s->vertical_bs) + goto fail; +#ifdef USE_PRED + s->tab_mvf_pool = av_buffer_pool_init(min_pu_size * sizeof(MvField), + av_buffer_allocz); + s->rpl_tab_pool = av_buffer_pool_init(ctb_count * sizeof(RefPicListTab), + av_buffer_allocz); + if (!s->tab_mvf_pool || !s->rpl_tab_pool) + goto fail; +#endif + + return 0; + +fail: + pic_arrays_free(s); + return AVERROR(ENOMEM); +} + +#ifdef USE_PRED +static void pred_weight_table(HEVCContext *s, GetBitContext *gb) +{ + int i = 0; + int j = 0; + uint8_t luma_weight_l0_flag[16]; + uint8_t chroma_weight_l0_flag[16]; + uint8_t luma_weight_l1_flag[16]; + uint8_t chroma_weight_l1_flag[16]; + + s->sh.luma_log2_weight_denom = get_ue_golomb_long(gb); + if (s->sps->chroma_format_idc != 0) { + int delta = get_se_golomb(gb); + s->sh.chroma_log2_weight_denom = av_clip(s->sh.luma_log2_weight_denom + delta, 0, 7); + } + + for (i = 0; i < s->sh.nb_refs[L0]; i++) { + luma_weight_l0_flag[i] = get_bits1(gb); + if (!luma_weight_l0_flag[i]) { + s->sh.luma_weight_l0[i] = 1 << s->sh.luma_log2_weight_denom; + s->sh.luma_offset_l0[i] = 0; + } + } + if (s->sps->chroma_format_idc != 0) { + for (i = 0; i < s->sh.nb_refs[L0]; i++) + chroma_weight_l0_flag[i] = get_bits1(gb); + } else { + for (i = 0; i < s->sh.nb_refs[L0]; i++) + chroma_weight_l0_flag[i] = 0; + } + for (i = 0; i < s->sh.nb_refs[L0]; i++) { + if (luma_weight_l0_flag[i]) { + int delta_luma_weight_l0 = get_se_golomb(gb); + s->sh.luma_weight_l0[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l0; + s->sh.luma_offset_l0[i] = get_se_golomb(gb); + } + if (chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + int delta_chroma_weight_l0 = get_se_golomb(gb); + int delta_chroma_offset_l0 = get_se_golomb(gb); + s->sh.chroma_weight_l0[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l0; + s->sh.chroma_offset_l0[i][j] = av_clip((delta_chroma_offset_l0 - ((128 * s->sh.chroma_weight_l0[i][j]) + >> s->sh.chroma_log2_weight_denom) + 128), -128, 127); + } + } else { + s->sh.chroma_weight_l0[i][0] = 1 << s->sh.chroma_log2_weight_denom; + s->sh.chroma_offset_l0[i][0] = 0; + s->sh.chroma_weight_l0[i][1] = 1 << s->sh.chroma_log2_weight_denom; + s->sh.chroma_offset_l0[i][1] = 0; + } + } + if (s->sh.slice_type == B_SLICE) { + for (i = 0; i < s->sh.nb_refs[L1]; i++) { + luma_weight_l1_flag[i] = get_bits1(gb); + if (!luma_weight_l1_flag[i]) { + s->sh.luma_weight_l1[i] = 1 << s->sh.luma_log2_weight_denom; + s->sh.luma_offset_l1[i] = 0; + } + } + if (s->sps->chroma_format_idc != 0) { + for (i = 0; i < s->sh.nb_refs[L1]; i++) + chroma_weight_l1_flag[i] = get_bits1(gb); + } else { + for (i = 0; i < s->sh.nb_refs[L1]; i++) + chroma_weight_l1_flag[i] = 0; + } + for (i = 0; i < s->sh.nb_refs[L1]; i++) { + if (luma_weight_l1_flag[i]) { + int delta_luma_weight_l1 = get_se_golomb(gb); + s->sh.luma_weight_l1[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l1; + s->sh.luma_offset_l1[i] = get_se_golomb(gb); + } + if (chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + int delta_chroma_weight_l1 = get_se_golomb(gb); + int delta_chroma_offset_l1 = get_se_golomb(gb); + s->sh.chroma_weight_l1[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l1; + s->sh.chroma_offset_l1[i][j] = av_clip((delta_chroma_offset_l1 - ((128 * s->sh.chroma_weight_l1[i][j]) + >> s->sh.chroma_log2_weight_denom) + 128), -128, 127); + } + } else { + s->sh.chroma_weight_l1[i][0] = 1 << s->sh.chroma_log2_weight_denom; + s->sh.chroma_offset_l1[i][0] = 0; + s->sh.chroma_weight_l1[i][1] = 1 << s->sh.chroma_log2_weight_denom; + s->sh.chroma_offset_l1[i][1] = 0; + } + } + } +} + +static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) +{ + const HEVCSPS *sps = s->sps; + int max_poc_lsb = 1 << sps->log2_max_poc_lsb; + int prev_delta_msb = 0; + unsigned int nb_sps = 0, nb_sh; + int i; + + rps->nb_refs = 0; + if (!sps->long_term_ref_pics_present_flag) + return 0; + + if (sps->num_long_term_ref_pics_sps > 0) + nb_sps = get_ue_golomb_long(gb); + nb_sh = get_ue_golomb_long(gb); + + if (nb_sh + (uint64_t)nb_sps > FF_ARRAY_ELEMS(rps->poc)) + return AVERROR_INVALIDDATA; + + rps->nb_refs = nb_sh + nb_sps; + + for (i = 0; i < rps->nb_refs; i++) { + uint8_t delta_poc_msb_present; + + if (i < nb_sps) { + uint8_t lt_idx_sps = 0; + + if (sps->num_long_term_ref_pics_sps > 1) + lt_idx_sps = get_bits(gb, av_ceil_log2(sps->num_long_term_ref_pics_sps)); + + rps->poc[i] = sps->lt_ref_pic_poc_lsb_sps[lt_idx_sps]; + rps->used[i] = sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps]; + } else { + rps->poc[i] = get_bits(gb, sps->log2_max_poc_lsb); + rps->used[i] = get_bits1(gb); + } + + delta_poc_msb_present = get_bits1(gb); + if (delta_poc_msb_present) { + int delta = get_ue_golomb_long(gb); + + if (i && i != nb_sps) + delta += prev_delta_msb; + + rps->poc[i] += s->poc - delta * max_poc_lsb - s->sh.pic_order_cnt_lsb; + prev_delta_msb = delta; + } + } + + return 0; +} +#endif + +static int get_buffer_sao(HEVCContext *s, AVFrame *frame, const HEVCSPS *sps) +{ + int ret, i; + + frame->width = s->avctx->coded_width + 2; + frame->height = s->avctx->coded_height + 2; + if ((ret = ff_get_buffer(s->avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + for (i = 0; frame->data[i]; i++) { + int offset = frame->linesize[i] + (1 << sps->pixel_shift); + frame->data[i] += offset; + } + frame->width = s->avctx->coded_width; + frame->height = s->avctx->coded_height; + + return 0; +} + +static int set_sps(HEVCContext *s, const HEVCSPS *sps) +{ + int ret; + + pic_arrays_free(s); + ret = pic_arrays_init(s, sps); + if (ret < 0) + goto fail; + + s->avctx->coded_width = sps->width; + s->avctx->coded_height = sps->height; + s->avctx->width = sps->output_width; + s->avctx->height = sps->output_height; + s->avctx->pix_fmt = sps->pix_fmt; + s->avctx->has_b_frames = sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics; + + ff_set_sar(s->avctx, sps->vui.sar); + + if (sps->vui.video_signal_type_present_flag) + s->avctx->color_range = sps->vui.video_full_range_flag ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + else + s->avctx->color_range = AVCOL_RANGE_MPEG; + + if (sps->vui.colour_description_present_flag) { + s->avctx->color_primaries = sps->vui.colour_primaries; + s->avctx->color_trc = sps->vui.transfer_characteristic; + s->avctx->colorspace = sps->vui.matrix_coeffs; + } else { + s->avctx->color_primaries = AVCOL_PRI_UNSPECIFIED; + s->avctx->color_trc = AVCOL_TRC_UNSPECIFIED; + s->avctx->colorspace = AVCOL_SPC_UNSPECIFIED; + } + +#ifdef USE_FUNC_PTR + ff_hevc_pred_init(&s->hpc, sps->bit_depth); +#endif + ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth); +#ifdef USE_PRED + ff_videodsp_init (&s->vdsp, sps->bit_depth); +#endif + + if (sps->sao_enabled) { +#ifdef USE_SAO_SMALL_BUFFER + { + int ctb_size = 1 << s->sps->log2_ctb_size; + int c_count = (s->sps->chroma_format_idc != 0) ? 3 : 1; + int c_idx; + + s->sao_pixel_buffer = + av_malloc(((ctb_size + 2) * (ctb_size + 2)) << + s->sps->pixel_shift); + for(c_idx = 0; c_idx < c_count; c_idx++) { + int w = s->sps->width >> s->sps->hshift[c_idx]; + int h = s->sps->height >> s->sps->vshift[c_idx]; + s->sao_pixel_buffer_h[c_idx] = + av_malloc((w * 2 * s->sps->ctb_height) << + s->sps->pixel_shift); + s->sao_pixel_buffer_v[c_idx] = + av_malloc((h * 2 * s->sps->ctb_width) << + s->sps->pixel_shift); + } + } +#else + av_frame_unref(s->tmp_frame); + ret = get_buffer_sao(s, s->tmp_frame, sps); + s->sao_frame = s->tmp_frame; +#endif + } + + s->sps = sps; + s->vps = (HEVCVPS*) s->vps_list[s->sps->vps_id]->data; + +#ifdef USE_FULL + { + unsigned int num = 0, den = 0; + if (s->vps->vps_timing_info_present_flag) { + num = s->vps->vps_num_units_in_tick; + den = s->vps->vps_time_scale; + } else if (sps->vui.vui_timing_info_present_flag) { + num = sps->vui.vui_num_units_in_tick; + den = sps->vui.vui_time_scale; + } + + if (num != 0 && den != 0) + av_reduce(&s->avctx->framerate.den, &s->avctx->framerate.num, + num, den, 1 << 30); + } +#endif + + return 0; + +fail: + pic_arrays_free(s); + s->sps = NULL; + return ret; +} + +static int hls_slice_header(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + SliceHeader *sh = &s->sh; + int i, j, ret; + + // Coded parameters + sh->first_slice_in_pic_flag = get_bits1(gb); + if ((IS_IDR(s) || IS_BLA(s)) && sh->first_slice_in_pic_flag) { + s->seq_decode = (s->seq_decode + 1) & 0xff; + s->max_ra = INT_MAX; + if (IS_IDR(s)) + ff_hevc_clear_refs(s); + } + sh->no_output_of_prior_pics_flag = 0; + if (IS_IRAP(s)) + sh->no_output_of_prior_pics_flag = get_bits1(gb); + + sh->pps_id = get_ue_golomb_long(gb); + if (sh->pps_id >= MAX_PPS_COUNT || !s->pps_list[sh->pps_id]) { + av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id); + return AVERROR_INVALIDDATA; + } + if (!sh->first_slice_in_pic_flag && + s->pps != (HEVCPPS*)s->pps_list[sh->pps_id]->data) { + av_log(s->avctx, AV_LOG_ERROR, "PPS changed between slices.\n"); + return AVERROR_INVALIDDATA; + } + s->pps = (HEVCPPS*)s->pps_list[sh->pps_id]->data; + if (s->nal_unit_type == NAL_CRA_NUT && s->last_eos == 1) + sh->no_output_of_prior_pics_flag = 1; + + if (s->sps != (HEVCSPS*)s->sps_list[s->pps->sps_id]->data) { + const HEVCSPS* last_sps = s->sps; + s->sps = (HEVCSPS*)s->sps_list[s->pps->sps_id]->data; + if (last_sps && IS_IRAP(s) && s->nal_unit_type != NAL_CRA_NUT) { + if (s->sps->width != last_sps->width || s->sps->height != last_sps->height || + s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering != + last_sps->temporal_layer[last_sps->max_sub_layers - 1].max_dec_pic_buffering) + sh->no_output_of_prior_pics_flag = 0; + } + ff_hevc_clear_refs(s); + ret = set_sps(s, s->sps); + if (ret < 0) + return ret; + + s->seq_decode = (s->seq_decode + 1) & 0xff; + s->max_ra = INT_MAX; + } + + s->avctx->profile = s->sps->ptl.general_ptl.profile_idc; + s->avctx->level = s->sps->ptl.general_ptl.level_idc; + + sh->dependent_slice_segment_flag = 0; + if (!sh->first_slice_in_pic_flag) { + int slice_address_length; + + if (s->pps->dependent_slice_segments_enabled_flag) + sh->dependent_slice_segment_flag = get_bits1(gb); + + slice_address_length = av_ceil_log2(s->sps->ctb_width * + s->sps->ctb_height); + sh->slice_segment_addr = get_bits(gb, slice_address_length); + if (sh->slice_segment_addr >= s->sps->ctb_width * s->sps->ctb_height) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid slice segment address: %u.\n", + sh->slice_segment_addr); + return AVERROR_INVALIDDATA; + } + + if (!sh->dependent_slice_segment_flag) { + sh->slice_addr = sh->slice_segment_addr; + s->slice_idx++; + } + } else { + sh->slice_segment_addr = sh->slice_addr = 0; + s->slice_idx = 0; + s->slice_initialized = 0; + } + + if (!sh->dependent_slice_segment_flag) { + s->slice_initialized = 0; + + for (i = 0; i < s->pps->num_extra_slice_header_bits; i++) + skip_bits(gb, 1); // slice_reserved_undetermined_flag[] + + sh->slice_type = get_ue_golomb_long(gb); + if (!(sh->slice_type == I_SLICE || + sh->slice_type == P_SLICE || + sh->slice_type == B_SLICE)) { + av_log(s->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n", + sh->slice_type); + return AVERROR_INVALIDDATA; + } + if (IS_IRAP(s) && sh->slice_type != I_SLICE) { + av_log(s->avctx, AV_LOG_ERROR, "Inter slices in an IRAP frame.\n"); + return AVERROR_INVALIDDATA; + } + + // when flag is not present, picture is inferred to be output + sh->pic_output_flag = 1; + if (s->pps->output_flag_present_flag) + sh->pic_output_flag = get_bits1(gb); + + if (s->sps->separate_colour_plane_flag) + sh->colour_plane_id = get_bits(gb, 2); + + if (!IS_IDR(s)) { +#ifdef USE_PRED + int short_term_ref_pic_set_sps_flag, poc; + + sh->pic_order_cnt_lsb = get_bits(gb, s->sps->log2_max_poc_lsb); + poc = ff_hevc_compute_poc(s, sh->pic_order_cnt_lsb); + if (!sh->first_slice_in_pic_flag && poc != s->poc) { + av_log(s->avctx, AV_LOG_WARNING, + "Ignoring POC change between slices: %d -> %d\n", s->poc, poc); + if (s->avctx->err_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + poc = s->poc; + } + s->poc = poc; + + short_term_ref_pic_set_sps_flag = get_bits1(gb); + if (!short_term_ref_pic_set_sps_flag) { + ret = ff_hevc_decode_short_term_rps(s, &sh->slice_rps, s->sps, 1); + if (ret < 0) + return ret; + + sh->short_term_rps = &sh->slice_rps; + } else { + int numbits, rps_idx; + + if (!s->sps->nb_st_rps) { + av_log(s->avctx, AV_LOG_ERROR, "No ref lists in the SPS.\n"); + return AVERROR_INVALIDDATA; + } + + numbits = av_ceil_log2(s->sps->nb_st_rps); + rps_idx = numbits > 0 ? get_bits(gb, numbits) : 0; + sh->short_term_rps = &s->sps->st_rps[rps_idx]; + } + + ret = decode_lt_rps(s, &sh->long_term_rps, gb); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid long term RPS.\n"); + if (s->avctx->err_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + } + + if (s->sps->sps_temporal_mvp_enabled_flag) + sh->slice_temporal_mvp_enabled_flag = get_bits1(gb); + else + sh->slice_temporal_mvp_enabled_flag = 0; +#else + abort(); +#endif + } else { + s->sh.short_term_rps = NULL; + s->poc = 0; + } + + /* 8.3.1 */ + if (s->temporal_id == 0 && + s->nal_unit_type != NAL_TRAIL_N && + s->nal_unit_type != NAL_TSA_N && + s->nal_unit_type != NAL_STSA_N && + s->nal_unit_type != NAL_RADL_N && + s->nal_unit_type != NAL_RADL_R && + s->nal_unit_type != NAL_RASL_N && + s->nal_unit_type != NAL_RASL_R) + s->pocTid0 = s->poc; + + if (s->sps->sao_enabled) { + sh->slice_sample_adaptive_offset_flag[0] = get_bits1(gb); + if (s->sps->chroma_format_idc != 0) { + sh->slice_sample_adaptive_offset_flag[1] = + sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb); + } else { + sh->slice_sample_adaptive_offset_flag[1] = 0; + sh->slice_sample_adaptive_offset_flag[2] = 0; + } + } else { + sh->slice_sample_adaptive_offset_flag[0] = 0; + sh->slice_sample_adaptive_offset_flag[1] = 0; + sh->slice_sample_adaptive_offset_flag[2] = 0; + } + + sh->nb_refs[L0] = sh->nb_refs[L1] = 0; +#ifdef USE_PRED + if (sh->slice_type == P_SLICE || sh->slice_type == B_SLICE) { + int nb_refs; + + sh->nb_refs[L0] = s->pps->num_ref_idx_l0_default_active; + if (sh->slice_type == B_SLICE) + sh->nb_refs[L1] = s->pps->num_ref_idx_l1_default_active; + + if (get_bits1(gb)) { // num_ref_idx_active_override_flag + sh->nb_refs[L0] = get_ue_golomb_long(gb) + 1; + if (sh->slice_type == B_SLICE) + sh->nb_refs[L1] = get_ue_golomb_long(gb) + 1; + } + if (sh->nb_refs[L0] > MAX_REFS || sh->nb_refs[L1] > MAX_REFS) { + av_log(s->avctx, AV_LOG_ERROR, "Too many refs: %d/%d.\n", + sh->nb_refs[L0], sh->nb_refs[L1]); + return AVERROR_INVALIDDATA; + } + + sh->rpl_modification_flag[0] = 0; + sh->rpl_modification_flag[1] = 0; + nb_refs = ff_hevc_frame_nb_refs(s); + if (!nb_refs) { + av_log(s->avctx, AV_LOG_ERROR, "Zero refs for a frame with P or B slices.\n"); + return AVERROR_INVALIDDATA; + } + + if (s->pps->lists_modification_present_flag && nb_refs > 1) { + sh->rpl_modification_flag[0] = get_bits1(gb); + if (sh->rpl_modification_flag[0]) { + for (i = 0; i < sh->nb_refs[L0]; i++) + sh->list_entry_lx[0][i] = get_bits(gb, av_ceil_log2(nb_refs)); + } + + if (sh->slice_type == B_SLICE) { + sh->rpl_modification_flag[1] = get_bits1(gb); + if (sh->rpl_modification_flag[1] == 1) + for (i = 0; i < sh->nb_refs[L1]; i++) + sh->list_entry_lx[1][i] = get_bits(gb, av_ceil_log2(nb_refs)); + } + } + + if (sh->slice_type == B_SLICE) + sh->mvd_l1_zero_flag = get_bits1(gb); + + if (s->pps->cabac_init_present_flag) + sh->cabac_init_flag = get_bits1(gb); + else + sh->cabac_init_flag = 0; + + sh->collocated_ref_idx = 0; + if (sh->slice_temporal_mvp_enabled_flag) { + sh->collocated_list = L0; + if (sh->slice_type == B_SLICE) + sh->collocated_list = !get_bits1(gb); + + if (sh->nb_refs[sh->collocated_list] > 1) { + sh->collocated_ref_idx = get_ue_golomb_long(gb); + if (sh->collocated_ref_idx >= sh->nb_refs[sh->collocated_list]) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid collocated_ref_idx: %d.\n", + sh->collocated_ref_idx); + return AVERROR_INVALIDDATA; + } + } + } + + if ((s->pps->weighted_pred_flag && sh->slice_type == P_SLICE) || + (s->pps->weighted_bipred_flag && sh->slice_type == B_SLICE)) { + pred_weight_table(s, gb); + } + + sh->max_num_merge_cand = 5 - get_ue_golomb_long(gb); + if (sh->max_num_merge_cand < 1 || sh->max_num_merge_cand > 5) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid number of merging MVP candidates: %d.\n", + sh->max_num_merge_cand); + return AVERROR_INVALIDDATA; + } + } +#endif + + sh->slice_qp_delta = get_se_golomb(gb); + + if (s->pps->pic_slice_level_chroma_qp_offsets_present_flag) { + sh->slice_cb_qp_offset = get_se_golomb(gb); + sh->slice_cr_qp_offset = get_se_golomb(gb); + } else { + sh->slice_cb_qp_offset = 0; + sh->slice_cr_qp_offset = 0; + } + + if (s->pps->chroma_qp_offset_list_enabled_flag) + sh->cu_chroma_qp_offset_enabled_flag = get_bits1(gb); + else + sh->cu_chroma_qp_offset_enabled_flag = 0; + + if (s->pps->deblocking_filter_control_present_flag) { + int deblocking_filter_override_flag = 0; + + if (s->pps->deblocking_filter_override_enabled_flag) + deblocking_filter_override_flag = get_bits1(gb); + + if (deblocking_filter_override_flag) { + sh->disable_deblocking_filter_flag = get_bits1(gb); + if (!sh->disable_deblocking_filter_flag) { + sh->beta_offset = get_se_golomb(gb) * 2; + sh->tc_offset = get_se_golomb(gb) * 2; + } + } else { + sh->disable_deblocking_filter_flag = s->pps->disable_dbf; + sh->beta_offset = s->pps->beta_offset; + sh->tc_offset = s->pps->tc_offset; + } + } else { + sh->disable_deblocking_filter_flag = 0; + sh->beta_offset = 0; + sh->tc_offset = 0; + } + + if (s->pps->seq_loop_filter_across_slices_enabled_flag && + (sh->slice_sample_adaptive_offset_flag[0] || + sh->slice_sample_adaptive_offset_flag[1] || + !sh->disable_deblocking_filter_flag)) { + sh->slice_loop_filter_across_slices_enabled_flag = get_bits1(gb); + } else { + sh->slice_loop_filter_across_slices_enabled_flag = s->pps->seq_loop_filter_across_slices_enabled_flag; + } + } else if (!s->slice_initialized) { + av_log(s->avctx, AV_LOG_ERROR, "Independent slice segment missing.\n"); + return AVERROR_INVALIDDATA; + } + + sh->num_entry_point_offsets = 0; + if (s->pps->tiles_enabled_flag || s->pps->entropy_coding_sync_enabled_flag) { + sh->num_entry_point_offsets = get_ue_golomb_long(gb); + if (sh->num_entry_point_offsets > 0) { + int offset_len = get_ue_golomb_long(gb) + 1; + int segments = offset_len >> 4; + int rest = (offset_len & 15); + av_freep(&sh->entry_point_offset); + av_freep(&sh->offset); + av_freep(&sh->size); + sh->entry_point_offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int)); + sh->offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int)); + sh->size = av_malloc_array(sh->num_entry_point_offsets, sizeof(int)); + if (!sh->entry_point_offset || !sh->offset || !sh->size) { + sh->num_entry_point_offsets = 0; + av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate memory\n"); + return AVERROR(ENOMEM); + } + for (i = 0; i < sh->num_entry_point_offsets; i++) { + int val = 0; + for (j = 0; j < segments; j++) { + val <<= 16; + val += get_bits(gb, 16); + } + if (rest) { + val <<= rest; + val += get_bits(gb, rest); + } + sh->entry_point_offset[i] = val + 1; // +1; // +1 to get the size + } + if (s->threads_number > 1 && (s->pps->num_tile_rows > 1 || s->pps->num_tile_columns > 1)) { + s->enable_parallel_tiles = 0; // TODO: you can enable tiles in parallel here + s->threads_number = 1; + } else + s->enable_parallel_tiles = 0; + } else + s->enable_parallel_tiles = 0; + } + + if (s->pps->slice_header_extension_present_flag) { + unsigned int length = get_ue_golomb_long(gb); + if (length*8LL > get_bits_left(gb)) { + av_log(s->avctx, AV_LOG_ERROR, "too many slice_header_extension_data_bytes\n"); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < length; i++) + skip_bits(gb, 8); // slice_header_extension_data_byte + } + + // Inferred parameters + sh->slice_qp = 26U + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta; + if (sh->slice_qp > 51 || + sh->slice_qp < -s->sps->qp_bd_offset) { + av_log(s->avctx, AV_LOG_ERROR, + "The slice_qp %d is outside the valid range " + "[%d, 51].\n", + sh->slice_qp, + -s->sps->qp_bd_offset); + return AVERROR_INVALIDDATA; + } + + sh->slice_ctb_addr_rs = sh->slice_segment_addr; + + if (!s->sh.slice_ctb_addr_rs && s->sh.dependent_slice_segment_flag) { + av_log(s->avctx, AV_LOG_ERROR, "Impossible slice segment.\n"); + return AVERROR_INVALIDDATA; + } + + if (get_bits_left(gb) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Overread slice header by %d bits\n", -get_bits_left(gb)); + return AVERROR_INVALIDDATA; + } + + s->HEVClc->first_qp_group = !s->sh.dependent_slice_segment_flag; + + if (!s->pps->cu_qp_delta_enabled_flag) + s->HEVClc->qp_y = s->sh.slice_qp; + + s->slice_initialized = 1; + s->HEVClc->tu.cu_qp_offset_cb = 0; + s->HEVClc->tu.cu_qp_offset_cr = 0; + + return 0; +} + +#define CTB(tab, x, y) ((tab)[(y) * s->sps->ctb_width + (x)]) + +#define SET_SAO(elem, value) \ +do { \ + if (!sao_merge_up_flag && !sao_merge_left_flag) \ + sao->elem = value; \ + else if (sao_merge_left_flag) \ + sao->elem = CTB(s->sao, rx-1, ry).elem; \ + else if (sao_merge_up_flag) \ + sao->elem = CTB(s->sao, rx, ry-1).elem; \ + else \ + sao->elem = 0; \ +} while (0) + +static void hls_sao_param(HEVCContext *s, int rx, int ry) +{ + HEVCLocalContext *lc = s->HEVClc; + int sao_merge_left_flag = 0; + int sao_merge_up_flag = 0; + SAOParams *sao = &CTB(s->sao, rx, ry); + int c_idx, i, c_count; + + if (s->sh.slice_sample_adaptive_offset_flag[0] || + s->sh.slice_sample_adaptive_offset_flag[1]) { + if (rx > 0) { + if (lc->ctb_left_flag) + sao_merge_left_flag = ff_hevc_sao_merge_flag_decode(s); + } + if (ry > 0 && !sao_merge_left_flag) { + if (lc->ctb_up_flag) + sao_merge_up_flag = ff_hevc_sao_merge_flag_decode(s); + } + } + + c_count = (s->sps->chroma_format_idc != 0) ? 3 : 1; + for (c_idx = 0; c_idx < c_count; c_idx++) { + int log2_sao_offset_scale = c_idx == 0 ? s->pps->log2_sao_offset_scale_luma : + s->pps->log2_sao_offset_scale_chroma; + if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) { + sao->type_idx[c_idx] = SAO_NOT_APPLIED; + continue; + } + + if (c_idx == 2) { + sao->type_idx[2] = sao->type_idx[1]; + sao->eo_class[2] = sao->eo_class[1]; + } else { + SET_SAO(type_idx[c_idx], ff_hevc_sao_type_idx_decode(s)); + } + + if (sao->type_idx[c_idx] == SAO_NOT_APPLIED) + continue; + + for (i = 0; i < 4; i++) + SET_SAO(offset_abs[c_idx][i], ff_hevc_sao_offset_abs_decode(s)); + + if (sao->type_idx[c_idx] == SAO_BAND) { + for (i = 0; i < 4; i++) { + if (sao->offset_abs[c_idx][i]) { + SET_SAO(offset_sign[c_idx][i], + ff_hevc_sao_offset_sign_decode(s)); + } else { + sao->offset_sign[c_idx][i] = 0; + } + } + SET_SAO(band_position[c_idx], ff_hevc_sao_band_position_decode(s)); + } else if (c_idx != 2) { + SET_SAO(eo_class[c_idx], ff_hevc_sao_eo_class_decode(s)); + } + + // Inferred parameters + sao->offset_val[c_idx][0] = 0; + for (i = 0; i < 4; i++) { + sao->offset_val[c_idx][i + 1] = sao->offset_abs[c_idx][i]; + if (sao->type_idx[c_idx] == SAO_EDGE) { + if (i > 1) + sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1]; + } else if (sao->offset_sign[c_idx][i]) { + sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1]; + } + sao->offset_val[c_idx][i + 1] <<= log2_sao_offset_scale; + } + } +} + +#undef SET_SAO +#undef CTB + +static int hls_cross_component_pred(HEVCContext *s, int idx) { + HEVCLocalContext *lc = s->HEVClc; + int log2_res_scale_abs_plus1 = ff_hevc_log2_res_scale_abs(s, idx); + + if (log2_res_scale_abs_plus1 != 0) { + int res_scale_sign_flag = ff_hevc_res_scale_sign_flag(s, idx); + lc->tu.res_scale_val = (1 << (log2_res_scale_abs_plus1 - 1)) * + (1 - 2 * res_scale_sign_flag); + } else { + lc->tu.res_scale_val = 0; + } + + + return 0; +} + +#ifdef USE_FUNC_PTR +#define INTRA_PRED(log2_trafo_size, s, x, y, c_idx) s->hpc.intra_pred[log2_trafo_size - 2](s, x, y, c_idx) +#else +#define INTRA_PRED(log2_trafo_size, s, x, y, c_idx) intra_pred(s, x, y, log2_trafo_size, c_idx) +#endif + +static int hls_transform_unit(HEVCContext *s, int x0, int y0, + int xBase, int yBase, int cb_xBase, int cb_yBase, + int log2_cb_size, int log2_trafo_size, + int trafo_depth, int blk_idx, + int cbf_luma, int *cbf_cb, int *cbf_cr) +{ + HEVCLocalContext *lc = s->HEVClc; + const int log2_trafo_size_c = log2_trafo_size - s->sps->hshift[1]; + int i; + + if (lc->cu.pred_mode == MODE_INTRA) { + int trafo_size = 1 << log2_trafo_size; + ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size); + + INTRA_PRED(log2_trafo_size, s, x0, y0, 0); + } + + if (cbf_luma || cbf_cb[0] || cbf_cr[0] || + (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { + int scan_idx = SCAN_DIAG; + int scan_idx_c = SCAN_DIAG; + int cbf_chroma = cbf_cb[0] || cbf_cr[0] || + (s->sps->chroma_format_idc == 2 && + (cbf_cb[1] || cbf_cr[1])); + + if (s->pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) { + lc->tu.cu_qp_delta = ff_hevc_cu_qp_delta_abs(s); + if (lc->tu.cu_qp_delta != 0) + if (ff_hevc_cu_qp_delta_sign_flag(s) == 1) + lc->tu.cu_qp_delta = -lc->tu.cu_qp_delta; + lc->tu.is_cu_qp_delta_coded = 1; + + if (lc->tu.cu_qp_delta < -(26 + s->sps->qp_bd_offset / 2) || + lc->tu.cu_qp_delta > (25 + s->sps->qp_bd_offset / 2)) { + av_log(s->avctx, AV_LOG_ERROR, + "The cu_qp_delta %d is outside the valid range " + "[%d, %d].\n", + lc->tu.cu_qp_delta, + -(26 + s->sps->qp_bd_offset / 2), + (25 + s->sps->qp_bd_offset / 2)); + return AVERROR_INVALIDDATA; + } + + ff_hevc_set_qPy(s, cb_xBase, cb_yBase, log2_cb_size); + } + + if (s->sh.cu_chroma_qp_offset_enabled_flag && cbf_chroma && + !lc->cu.cu_transquant_bypass_flag && !lc->tu.is_cu_chroma_qp_offset_coded) { + int cu_chroma_qp_offset_flag = ff_hevc_cu_chroma_qp_offset_flag(s); + if (cu_chroma_qp_offset_flag) { + int cu_chroma_qp_offset_idx = 0; + if (s->pps->chroma_qp_offset_list_len_minus1 > 0) { + cu_chroma_qp_offset_idx = ff_hevc_cu_chroma_qp_offset_idx(s); + av_log(s->avctx, AV_LOG_ERROR, + "cu_chroma_qp_offset_idx not yet tested.\n"); + } + lc->tu.cu_qp_offset_cb = s->pps->cb_qp_offset_list[cu_chroma_qp_offset_idx]; + lc->tu.cu_qp_offset_cr = s->pps->cr_qp_offset_list[cu_chroma_qp_offset_idx]; + } else { + lc->tu.cu_qp_offset_cb = 0; + lc->tu.cu_qp_offset_cr = 0; + } + lc->tu.is_cu_chroma_qp_offset_coded = 1; + } + + if (lc->cu.pred_mode == MODE_INTRA && log2_trafo_size < 4) { + if (lc->tu.intra_pred_mode >= 6 && + lc->tu.intra_pred_mode <= 14) { + scan_idx = SCAN_VERT; + } else if (lc->tu.intra_pred_mode >= 22 && + lc->tu.intra_pred_mode <= 30) { + scan_idx = SCAN_HORIZ; + } + + if (lc->tu.intra_pred_mode_c >= 6 && + lc->tu.intra_pred_mode_c <= 14) { + scan_idx_c = SCAN_VERT; + } else if (lc->tu.intra_pred_mode_c >= 22 && + lc->tu.intra_pred_mode_c <= 30) { + scan_idx_c = SCAN_HORIZ; + } + } + + lc->tu.cross_pf = 0; + + if (cbf_luma) + ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0); + if (s->sps->chroma_format_idc != 0) { + if (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3) { + int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]); + int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]); + lc->tu.cross_pf = (s->pps->cross_component_prediction_enabled_flag && cbf_luma && + (lc->cu.pred_mode == MODE_INTER || + (lc->tu.chroma_mode_c == 4))); + + if (lc->tu.cross_pf) { + hls_cross_component_pred(s, 0); + } + for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) { + if (lc->cu.pred_mode == MODE_INTRA) { + ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size_c, s, x0, y0 + (i << log2_trafo_size_c), 1); + } + if (cbf_cb[i]) + ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c), + log2_trafo_size_c, scan_idx_c, 1); + else + if (lc->tu.cross_pf) { + ptrdiff_t stride = s->frame->linesize[1]; + int hshift = s->sps->hshift[1]; + int vshift = s->sps->vshift[1]; + int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer; + int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2; + int size = 1 << log2_trafo_size_c; + + uint8_t *dst = &s->frame->data[1][(y0 >> vshift) * stride + + ((x0 >> hshift) << s->sps->pixel_shift)]; + for (i = 0; i < (size * size); i++) { + coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3); + } + s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride BIT_DEPTH_ARG2(s->sps->bit_depth)); + } + } + + if (lc->tu.cross_pf) { + hls_cross_component_pred(s, 1); + } + for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) { + if (lc->cu.pred_mode == MODE_INTRA) { + ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size_c, s, x0, y0 + (i << log2_trafo_size_c), 2); + } + if (cbf_cr[i]) + ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c), + log2_trafo_size_c, scan_idx_c, 2); + else + if (lc->tu.cross_pf) { + ptrdiff_t stride = s->frame->linesize[2]; + int hshift = s->sps->hshift[2]; + int vshift = s->sps->vshift[2]; + int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer; + int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2; + int size = 1 << log2_trafo_size_c; + + uint8_t *dst = &s->frame->data[2][(y0 >> vshift) * stride + + ((x0 >> hshift) << s->sps->pixel_shift)]; + for (i = 0; i < (size * size); i++) { + coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3); + } + s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride BIT_DEPTH_ARG2(s->sps->bit_depth)); + } + } + } else if (blk_idx == 3) { + int trafo_size_h = 1 << (log2_trafo_size + 1); + int trafo_size_v = 1 << (log2_trafo_size + s->sps->vshift[1]); + for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) { + if (lc->cu.pred_mode == MODE_INTRA) { + ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size), + trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size, s, xBase, yBase + (i << log2_trafo_size), 1); + } + if (cbf_cb[i]) + ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size), + log2_trafo_size, scan_idx_c, 1); + } + for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) { + if (lc->cu.pred_mode == MODE_INTRA) { + ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size), + trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size, s, xBase, yBase + (i << log2_trafo_size), 2); + } + if (cbf_cr[i]) + ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size), + log2_trafo_size, scan_idx_c, 2); + } + } + } /* chroma_firmat_idc != 0 */ + } else if (lc->cu.pred_mode == MODE_INTRA && + s->sps->chroma_format_idc != 0) { + if (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3) { + int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]); + int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]); + ff_hevc_set_neighbour_available(s, x0, y0, trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size_c, s, x0, y0, 1); + INTRA_PRED(log2_trafo_size_c, s, x0, y0, 2); + if (s->sps->chroma_format_idc == 2) { + ff_hevc_set_neighbour_available(s, x0, y0 + (1 << log2_trafo_size_c), + trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size_c, s, x0, y0 + (1 << log2_trafo_size_c), 1); + INTRA_PRED(log2_trafo_size_c, s, x0, y0 + (1 << log2_trafo_size_c), 2); + } + } else if (blk_idx == 3) { + int trafo_size_h = 1 << (log2_trafo_size + 1); + int trafo_size_v = 1 << (log2_trafo_size + s->sps->vshift[1]); + ff_hevc_set_neighbour_available(s, xBase, yBase, + trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size, s, xBase, yBase, 1); + INTRA_PRED(log2_trafo_size, s, xBase, yBase, 2); + if (s->sps->chroma_format_idc == 2) { + ff_hevc_set_neighbour_available(s, xBase, yBase + (1 << (log2_trafo_size)), + trafo_size_h, trafo_size_v); + INTRA_PRED(log2_trafo_size, s, xBase, yBase + (1 << (log2_trafo_size)), 1); + INTRA_PRED(log2_trafo_size, s, xBase, yBase + (1 << (log2_trafo_size)), 2); + } + } + } + + return 0; +} + +static void set_deblocking_bypass(HEVCContext *s, int x0, int y0, int log2_cb_size) +{ + int cb_size = 1 << log2_cb_size; + int log2_min_pu_size = s->sps->log2_min_pu_size; + + int min_pu_width = s->sps->min_pu_width; + int x_end = FFMIN(x0 + cb_size, s->sps->width); + int y_end = FFMIN(y0 + cb_size, s->sps->height); + int i, j; + + for (j = (y0 >> log2_min_pu_size); j < (y_end >> log2_min_pu_size); j++) + for (i = (x0 >> log2_min_pu_size); i < (x_end >> log2_min_pu_size); i++) + s->is_pcm[i + j * min_pu_width] = 2; +} + +static int hls_transform_tree(HEVCContext *s, int x0, int y0, + int xBase, int yBase, int cb_xBase, int cb_yBase, + int log2_cb_size, int log2_trafo_size, + int trafo_depth, int blk_idx, + const int *base_cbf_cb, const int *base_cbf_cr) +{ + HEVCLocalContext *lc = s->HEVClc; + uint8_t split_transform_flag; + int cbf_cb[2]; + int cbf_cr[2]; + int ret; + + cbf_cb[0] = base_cbf_cb[0]; + cbf_cb[1] = base_cbf_cb[1]; + cbf_cr[0] = base_cbf_cr[0]; + cbf_cr[1] = base_cbf_cr[1]; + + if (lc->cu.intra_split_flag) { + if (trafo_depth == 1) { + lc->tu.intra_pred_mode = lc->pu.intra_pred_mode[blk_idx]; + if (s->sps->chroma_format_idc == 3) { + lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[blk_idx]; + lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[blk_idx]; + } else { + lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0]; + lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[0]; + } + } + } else { + lc->tu.intra_pred_mode = lc->pu.intra_pred_mode[0]; + lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0]; + lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[0]; + } + + if (log2_trafo_size <= s->sps->log2_max_trafo_size && + log2_trafo_size > s->sps->log2_min_tb_size && + trafo_depth < lc->cu.max_trafo_depth && + !(lc->cu.intra_split_flag && trafo_depth == 0)) { + split_transform_flag = ff_hevc_split_transform_flag_decode(s, log2_trafo_size); + } else { + int inter_split = s->sps->max_transform_hierarchy_depth_inter == 0 && + lc->cu.pred_mode == MODE_INTER && + lc->cu.part_mode != PART_2Nx2N && + trafo_depth == 0; + + split_transform_flag = log2_trafo_size > s->sps->log2_max_trafo_size || + (lc->cu.intra_split_flag && trafo_depth == 0) || + inter_split; + } + + if ((log2_trafo_size > 2 || s->sps->chroma_format_idc == 3) && + s->sps->chroma_format_idc != 0) { + if (trafo_depth == 0 || cbf_cb[0]) { + cbf_cb[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth); + if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { + cbf_cb[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth); + } + } + + if (trafo_depth == 0 || cbf_cr[0]) { + cbf_cr[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth); + if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { + cbf_cr[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth); + } + } + } + + if (split_transform_flag) { + const int trafo_size_split = 1 << (log2_trafo_size - 1); + const int x1 = x0 + trafo_size_split; + const int y1 = y0 + trafo_size_split; + +#define SUBDIVIDE(x, y, idx) \ +do { \ + ret = hls_transform_tree(s, x, y, x0, y0, cb_xBase, cb_yBase, log2_cb_size, \ + log2_trafo_size - 1, trafo_depth + 1, idx, \ + cbf_cb, cbf_cr); \ + if (ret < 0) \ + return ret; \ +} while (0) + + SUBDIVIDE(x0, y0, 0); + SUBDIVIDE(x1, y0, 1); + SUBDIVIDE(x0, y1, 2); + SUBDIVIDE(x1, y1, 3); + +#undef SUBDIVIDE + } else { + int min_tu_size = 1 << s->sps->log2_min_tb_size; + int log2_min_tu_size = s->sps->log2_min_tb_size; + int min_tu_width = s->sps->min_tb_width; + int cbf_luma = 1; + + if (lc->cu.pred_mode == MODE_INTRA || trafo_depth != 0 || + cbf_cb[0] || cbf_cr[0] || + (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { + cbf_luma = ff_hevc_cbf_luma_decode(s, trafo_depth); + } + + ret = hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase, + log2_cb_size, log2_trafo_size, trafo_depth, + blk_idx, cbf_luma, cbf_cb, cbf_cr); + if (ret < 0) + return ret; + // TODO: store cbf_luma somewhere else + if (cbf_luma) { + int i, j; + for (i = 0; i < (1 << log2_trafo_size); i += min_tu_size) + for (j = 0; j < (1 << log2_trafo_size); j += min_tu_size) { + int x_tu = (x0 + j) >> log2_min_tu_size; + int y_tu = (y0 + i) >> log2_min_tu_size; + s->cbf_luma[y_tu * min_tu_width + x_tu] = 1; + } + } + if (!s->sh.disable_deblocking_filter_flag) { + ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_trafo_size); + if (s->pps->transquant_bypass_enable_flag && + lc->cu.cu_transquant_bypass_flag) + set_deblocking_bypass(s, x0, y0, log2_trafo_size); + } + } + return 0; +} + +static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size) +{ + HEVCLocalContext *lc = s->HEVClc; + GetBitContext gb; + int cb_size = 1 << log2_cb_size; + int stride0 = s->frame->linesize[0]; + uint8_t *dst0 = &s->frame->data[0][y0 * stride0 + (x0 << s->sps->pixel_shift)]; + int stride1 = s->frame->linesize[1]; + uint8_t *dst1 = &s->frame->data[1][(y0 >> s->sps->vshift[1]) * stride1 + ((x0 >> s->sps->hshift[1]) << s->sps->pixel_shift)]; + int stride2 = s->frame->linesize[2]; + uint8_t *dst2 = &s->frame->data[2][(y0 >> s->sps->vshift[2]) * stride2 + ((x0 >> s->sps->hshift[2]) << s->sps->pixel_shift)]; + + int length = cb_size * cb_size * s->sps->pcm.bit_depth + + (((cb_size >> s->sps->hshift[1]) * (cb_size >> s->sps->vshift[1])) + + ((cb_size >> s->sps->hshift[2]) * (cb_size >> s->sps->vshift[2]))) * + s->sps->pcm.bit_depth_chroma; + const uint8_t *pcm = skip_bytes(&lc->cc, (length + 7) >> 3); + int ret; + + if (!s->sh.disable_deblocking_filter_flag) + ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size); + + ret = init_get_bits(&gb, pcm, length); + if (ret < 0) + return ret; + + s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, s->sps->pcm.bit_depth BIT_DEPTH_ARG2(s->sps->bit_depth)); + s->hevcdsp.put_pcm(dst1, stride1, + cb_size >> s->sps->hshift[1], + cb_size >> s->sps->vshift[1], + &gb, s->sps->pcm.bit_depth_chroma BIT_DEPTH_ARG2(s->sps->bit_depth)); + s->hevcdsp.put_pcm(dst2, stride2, + cb_size >> s->sps->hshift[2], + cb_size >> s->sps->vshift[2], + &gb, s->sps->pcm.bit_depth_chroma BIT_DEPTH_ARG2(s->sps->bit_depth)); + return 0; +} + +#ifdef USE_PRED +/** + * 8.5.3.2.2.1 Luma sample unidirectional interpolation process + * + * @param s HEVC decoding context + * @param dst target buffer for block data at block position + * @param dststride stride of the dst buffer + * @param ref reference picture buffer at origin (0, 0) + * @param mv motion vector (relative to block position) to get pixel data from + * @param x_off horizontal position of block from origin (0, 0) + * @param y_off vertical position of block from origin (0, 0) + * @param block_w width of block + * @param block_h height of block + * @param luma_weight weighting factor applied to the luma prediction + * @param luma_offset additive offset applied to the luma prediction value + */ + +static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride, + AVFrame *ref, const Mv *mv, int x_off, int y_off, + int block_w, int block_h, int luma_weight, int luma_offset) +{ + HEVCLocalContext *lc = s->HEVClc; + uint8_t *src = ref->data[0]; + ptrdiff_t srcstride = ref->linesize[0]; + int pic_width = s->sps->width; + int pic_height = s->sps->height; + int mx = mv->x & 3; + int my = mv->y & 3; + int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) || + (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag); + int idx = ff_hevc_pel_weight[block_w]; + + x_off += mv->x >> 2; + y_off += mv->y >> 2; + src += y_off * srcstride + (x_off << s->sps->pixel_shift); + + if (x_off < QPEL_EXTRA_BEFORE || y_off < QPEL_EXTRA_AFTER || + x_off >= pic_width - block_w - QPEL_EXTRA_AFTER || + y_off >= pic_height - block_h - QPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * srcstride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src - offset, + edge_emu_stride, srcstride, + block_w + QPEL_EXTRA, + block_h + QPEL_EXTRA, + x_off - QPEL_EXTRA_BEFORE, y_off - QPEL_EXTRA_BEFORE, + pic_width, pic_height); + src = lc->edge_emu_buffer + buf_offset; + srcstride = edge_emu_stride; + } + + if (!weight_flag) + s->hevcdsp.put_hevc_qpel_uni[idx][!!my][!!mx](dst, dststride, src, srcstride, + block_h, mx, my, block_w); + else + s->hevcdsp.put_hevc_qpel_uni_w[idx][!!my][!!mx](dst, dststride, src, srcstride, + block_h, s->sh.luma_log2_weight_denom, + luma_weight, luma_offset, mx, my, block_w); +} + +/** + * 8.5.3.2.2.1 Luma sample bidirectional interpolation process + * + * @param s HEVC decoding context + * @param dst target buffer for block data at block position + * @param dststride stride of the dst buffer + * @param ref0 reference picture0 buffer at origin (0, 0) + * @param mv0 motion vector0 (relative to block position) to get pixel data from + * @param x_off horizontal position of block from origin (0, 0) + * @param y_off vertical position of block from origin (0, 0) + * @param block_w width of block + * @param block_h height of block + * @param ref1 reference picture1 buffer at origin (0, 0) + * @param mv1 motion vector1 (relative to block position) to get pixel data from + * @param current_mv current motion vector structure + */ + static void luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride, + AVFrame *ref0, const Mv *mv0, int x_off, int y_off, + int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv) +{ + HEVCLocalContext *lc = s->HEVClc; + ptrdiff_t src0stride = ref0->linesize[0]; + ptrdiff_t src1stride = ref1->linesize[0]; + int pic_width = s->sps->width; + int pic_height = s->sps->height; + int mx0 = mv0->x & 3; + int my0 = mv0->y & 3; + int mx1 = mv1->x & 3; + int my1 = mv1->y & 3; + int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) || + (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag); + int x_off0 = x_off + (mv0->x >> 2); + int y_off0 = y_off + (mv0->y >> 2); + int x_off1 = x_off + (mv1->x >> 2); + int y_off1 = y_off + (mv1->y >> 2); + int idx = ff_hevc_pel_weight[block_w]; + + uint8_t *src0 = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->sps->pixel_shift); + uint8_t *src1 = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->sps->pixel_shift); + + if (x_off0 < QPEL_EXTRA_BEFORE || y_off0 < QPEL_EXTRA_AFTER || + x_off0 >= pic_width - block_w - QPEL_EXTRA_AFTER || + y_off0 >= pic_height - block_h - QPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * src0stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset, + edge_emu_stride, src0stride, + block_w + QPEL_EXTRA, + block_h + QPEL_EXTRA, + x_off0 - QPEL_EXTRA_BEFORE, y_off0 - QPEL_EXTRA_BEFORE, + pic_width, pic_height); + src0 = lc->edge_emu_buffer + buf_offset; + src0stride = edge_emu_stride; + } + + if (x_off1 < QPEL_EXTRA_BEFORE || y_off1 < QPEL_EXTRA_AFTER || + x_off1 >= pic_width - block_w - QPEL_EXTRA_AFTER || + y_off1 >= pic_height - block_h - QPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * src1stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift); + + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src1 - offset, + edge_emu_stride, src1stride, + block_w + QPEL_EXTRA, + block_h + QPEL_EXTRA, + x_off1 - QPEL_EXTRA_BEFORE, y_off1 - QPEL_EXTRA_BEFORE, + pic_width, pic_height); + src1 = lc->edge_emu_buffer2 + buf_offset; + src1stride = edge_emu_stride; + } + + s->hevcdsp.put_hevc_qpel[idx][!!my0][!!mx0](lc->tmp, src0, src0stride, + block_h, mx0, my0, block_w); + if (!weight_flag) + s->hevcdsp.put_hevc_qpel_bi[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp, + block_h, mx1, my1, block_w); + else + s->hevcdsp.put_hevc_qpel_bi_w[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp, + block_h, s->sh.luma_log2_weight_denom, + s->sh.luma_weight_l0[current_mv->ref_idx[0]], + s->sh.luma_weight_l1[current_mv->ref_idx[1]], + s->sh.luma_offset_l0[current_mv->ref_idx[0]], + s->sh.luma_offset_l1[current_mv->ref_idx[1]], + mx1, my1, block_w); + +} + +/** + * 8.5.3.2.2.2 Chroma sample uniprediction interpolation process + * + * @param s HEVC decoding context + * @param dst1 target buffer for block data at block position (U plane) + * @param dst2 target buffer for block data at block position (V plane) + * @param dststride stride of the dst1 and dst2 buffers + * @param ref reference picture buffer at origin (0, 0) + * @param mv motion vector (relative to block position) to get pixel data from + * @param x_off horizontal position of block from origin (0, 0) + * @param y_off vertical position of block from origin (0, 0) + * @param block_w width of block + * @param block_h height of block + * @param chroma_weight weighting factor applied to the chroma prediction + * @param chroma_offset additive offset applied to the chroma prediction value + */ + +static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0, + ptrdiff_t dststride, uint8_t *src0, ptrdiff_t srcstride, int reflist, + int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int chroma_weight, int chroma_offset) +{ + HEVCLocalContext *lc = s->HEVClc; + int pic_width = s->sps->width >> s->sps->hshift[1]; + int pic_height = s->sps->height >> s->sps->vshift[1]; + const Mv *mv = ¤t_mv->mv[reflist]; + int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) || + (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag); + int idx = ff_hevc_pel_weight[block_w]; + int hshift = s->sps->hshift[1]; + int vshift = s->sps->vshift[1]; + intptr_t mx = mv->x & ((1 << (2 + hshift)) - 1); + intptr_t my = mv->y & ((1 << (2 + vshift)) - 1); + intptr_t _mx = mx << (1 - hshift); + intptr_t _my = my << (1 - vshift); + + x_off += mv->x >> (2 + hshift); + y_off += mv->y >> (2 + vshift); + src0 += y_off * srcstride + (x_off << s->sps->pixel_shift); + + if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER || + x_off >= pic_width - block_w - EPEL_EXTRA_AFTER || + y_off >= pic_height - block_h - EPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->sps->pixel_shift)); + int buf_offset0 = EPEL_EXTRA_BEFORE * + (edge_emu_stride + (1 << s->sps->pixel_shift)); + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset0, + edge_emu_stride, srcstride, + block_w + EPEL_EXTRA, block_h + EPEL_EXTRA, + x_off - EPEL_EXTRA_BEFORE, + y_off - EPEL_EXTRA_BEFORE, + pic_width, pic_height); + + src0 = lc->edge_emu_buffer + buf_offset0; + srcstride = edge_emu_stride; + } + if (!weight_flag) + s->hevcdsp.put_hevc_epel_uni[idx][!!my][!!mx](dst0, dststride, src0, srcstride, + block_h, _mx, _my, block_w); + else + s->hevcdsp.put_hevc_epel_uni_w[idx][!!my][!!mx](dst0, dststride, src0, srcstride, + block_h, s->sh.chroma_log2_weight_denom, + chroma_weight, chroma_offset, _mx, _my, block_w); +} + +/** + * 8.5.3.2.2.2 Chroma sample bidirectional interpolation process + * + * @param s HEVC decoding context + * @param dst target buffer for block data at block position + * @param dststride stride of the dst buffer + * @param ref0 reference picture0 buffer at origin (0, 0) + * @param mv0 motion vector0 (relative to block position) to get pixel data from + * @param x_off horizontal position of block from origin (0, 0) + * @param y_off vertical position of block from origin (0, 0) + * @param block_w width of block + * @param block_h height of block + * @param ref1 reference picture1 buffer at origin (0, 0) + * @param mv1 motion vector1 (relative to block position) to get pixel data from + * @param current_mv current motion vector structure + * @param cidx chroma component(cb, cr) + */ +static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVFrame *ref0, AVFrame *ref1, + int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int cidx) +{ + HEVCLocalContext *lc = s->HEVClc; + uint8_t *src1 = ref0->data[cidx+1]; + uint8_t *src2 = ref1->data[cidx+1]; + ptrdiff_t src1stride = ref0->linesize[cidx+1]; + ptrdiff_t src2stride = ref1->linesize[cidx+1]; + int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) || + (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag); + int pic_width = s->sps->width >> s->sps->hshift[1]; + int pic_height = s->sps->height >> s->sps->vshift[1]; + Mv *mv0 = ¤t_mv->mv[0]; + Mv *mv1 = ¤t_mv->mv[1]; + int hshift = s->sps->hshift[1]; + int vshift = s->sps->vshift[1]; + + intptr_t mx0 = mv0->x & ((1 << (2 + hshift)) - 1); + intptr_t my0 = mv0->y & ((1 << (2 + vshift)) - 1); + intptr_t mx1 = mv1->x & ((1 << (2 + hshift)) - 1); + intptr_t my1 = mv1->y & ((1 << (2 + vshift)) - 1); + intptr_t _mx0 = mx0 << (1 - hshift); + intptr_t _my0 = my0 << (1 - vshift); + intptr_t _mx1 = mx1 << (1 - hshift); + intptr_t _my1 = my1 << (1 - vshift); + + int x_off0 = x_off + (mv0->x >> (2 + hshift)); + int y_off0 = y_off + (mv0->y >> (2 + vshift)); + int x_off1 = x_off + (mv1->x >> (2 + hshift)); + int y_off1 = y_off + (mv1->y >> (2 + vshift)); + int idx = ff_hevc_pel_weight[block_w]; + src1 += y_off0 * src1stride + (int)((unsigned)x_off0 << s->sps->pixel_shift); + src2 += y_off1 * src2stride + (int)((unsigned)x_off1 << s->sps->pixel_shift); + + if (x_off0 < EPEL_EXTRA_BEFORE || y_off0 < EPEL_EXTRA_AFTER || + x_off0 >= pic_width - block_w - EPEL_EXTRA_AFTER || + y_off0 >= pic_height - block_h - EPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift)); + int buf_offset1 = EPEL_EXTRA_BEFORE * + (edge_emu_stride + (1 << s->sps->pixel_shift)); + + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1 - offset1, + edge_emu_stride, src1stride, + block_w + EPEL_EXTRA, block_h + EPEL_EXTRA, + x_off0 - EPEL_EXTRA_BEFORE, + y_off0 - EPEL_EXTRA_BEFORE, + pic_width, pic_height); + + src1 = lc->edge_emu_buffer + buf_offset1; + src1stride = edge_emu_stride; + } + + if (x_off1 < EPEL_EXTRA_BEFORE || y_off1 < EPEL_EXTRA_AFTER || + x_off1 >= pic_width - block_w - EPEL_EXTRA_AFTER || + y_off1 >= pic_height - block_h - EPEL_EXTRA_AFTER) { + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift; + int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift)); + int buf_offset1 = EPEL_EXTRA_BEFORE * + (edge_emu_stride + (1 << s->sps->pixel_shift)); + + s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src2 - offset1, + edge_emu_stride, src2stride, + block_w + EPEL_EXTRA, block_h + EPEL_EXTRA, + x_off1 - EPEL_EXTRA_BEFORE, + y_off1 - EPEL_EXTRA_BEFORE, + pic_width, pic_height); + + src2 = lc->edge_emu_buffer2 + buf_offset1; + src2stride = edge_emu_stride; + } + + s->hevcdsp.put_hevc_epel[idx][!!my0][!!mx0](lc->tmp, src1, src1stride, + block_h, _mx0, _my0, block_w); + if (!weight_flag) + s->hevcdsp.put_hevc_epel_bi[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1], + src2, src2stride, lc->tmp, + block_h, _mx1, _my1, block_w); + else + s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1], + src2, src2stride, lc->tmp, + block_h, + s->sh.chroma_log2_weight_denom, + s->sh.chroma_weight_l0[current_mv->ref_idx[0]][cidx], + s->sh.chroma_weight_l1[current_mv->ref_idx[1]][cidx], + s->sh.chroma_offset_l0[current_mv->ref_idx[0]][cidx], + s->sh.chroma_offset_l1[current_mv->ref_idx[1]][cidx], + _mx1, _my1, block_w); +} +#endif + +#ifdef USE_FULL +static void hevc_await_progress(HEVCContext *s, HEVCFrame *ref, + const Mv *mv, int y0, int height) +{ + int y = FFMAX(0, (mv->y >> 2) + y0 + height + 9); + + if (s->threads_type == FF_THREAD_FRAME ) + ff_thread_await_progress(&ref->tf, y, 0); +} +#endif + +#ifdef USE_PRED +static void hls_prediction_unit(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH, + int log2_cb_size, int partIdx, int idx) +{ +#define POS(c_idx, x, y) \ + &s->frame->data[c_idx][((y) >> s->sps->vshift[c_idx]) * s->frame->linesize[c_idx] + \ + (((x) >> s->sps->hshift[c_idx]) << s->sps->pixel_shift)] + HEVCLocalContext *lc = s->HEVClc; + int merge_idx = 0; + struct MvField current_mv = {{{ 0 }}}; + + int min_pu_width = s->sps->min_pu_width; + + MvField *tab_mvf = s->ref->tab_mvf; + RefPicList *refPicList = s->ref->refPicList; + HEVCFrame *ref0, *ref1; + uint8_t *dst0 = POS(0, x0, y0); + uint8_t *dst1 = POS(1, x0, y0); + uint8_t *dst2 = POS(2, x0, y0); + int log2_min_cb_size = s->sps->log2_min_cb_size; + int min_cb_width = s->sps->min_cb_width; + int x_cb = x0 >> log2_min_cb_size; + int y_cb = y0 >> log2_min_cb_size; + int ref_idx[2]; + int mvp_flag[2]; + int x_pu, y_pu; + int i, j; + + if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) { + if (s->sh.max_num_merge_cand > 1) + merge_idx = ff_hevc_merge_idx_decode(s); + else + merge_idx = 0; + + ff_hevc_luma_mv_merge_mode(s, x0, y0, + 1 << log2_cb_size, + 1 << log2_cb_size, + log2_cb_size, partIdx, + merge_idx, ¤t_mv); + x_pu = x0 >> s->sps->log2_min_pu_size; + y_pu = y0 >> s->sps->log2_min_pu_size; + + for (j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++) + for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++) + tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv; + } else { /* MODE_INTER */ + lc->pu.merge_flag = ff_hevc_merge_flag_decode(s); + if (lc->pu.merge_flag) { + if (s->sh.max_num_merge_cand > 1) + merge_idx = ff_hevc_merge_idx_decode(s); + else + merge_idx = 0; + + ff_hevc_luma_mv_merge_mode(s, x0, y0, nPbW, nPbH, log2_cb_size, + partIdx, merge_idx, ¤t_mv); + x_pu = x0 >> s->sps->log2_min_pu_size; + y_pu = y0 >> s->sps->log2_min_pu_size; + + for (j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++) + for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++) + tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv; + } else { + enum InterPredIdc inter_pred_idc = PRED_L0; + ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH); + current_mv.pred_flag = 0; + if (s->sh.slice_type == B_SLICE) + inter_pred_idc = ff_hevc_inter_pred_idc_decode(s, nPbW, nPbH); + + if (inter_pred_idc != PRED_L1) { + if (s->sh.nb_refs[L0]) { + ref_idx[0] = ff_hevc_ref_idx_lx_decode(s, s->sh.nb_refs[L0]); + current_mv.ref_idx[0] = ref_idx[0]; + } + current_mv.pred_flag = PF_L0; + ff_hevc_hls_mvd_coding(s, x0, y0, 0); + mvp_flag[0] = ff_hevc_mvp_lx_flag_decode(s); + ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size, + partIdx, merge_idx, ¤t_mv, + mvp_flag[0], 0); + current_mv.mv[0].x += lc->pu.mvd.x; + current_mv.mv[0].y += lc->pu.mvd.y; + } + + if (inter_pred_idc != PRED_L0) { + if (s->sh.nb_refs[L1]) { + ref_idx[1] = ff_hevc_ref_idx_lx_decode(s, s->sh.nb_refs[L1]); + current_mv.ref_idx[1] = ref_idx[1]; + } + + if (s->sh.mvd_l1_zero_flag == 1 && inter_pred_idc == PRED_BI) { + AV_ZERO32(&lc->pu.mvd); + } else { + ff_hevc_hls_mvd_coding(s, x0, y0, 1); + } + + current_mv.pred_flag += PF_L1; + mvp_flag[1] = ff_hevc_mvp_lx_flag_decode(s); + ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size, + partIdx, merge_idx, ¤t_mv, + mvp_flag[1], 1); + current_mv.mv[1].x += lc->pu.mvd.x; + current_mv.mv[1].y += lc->pu.mvd.y; + } + + x_pu = x0 >> s->sps->log2_min_pu_size; + y_pu = y0 >> s->sps->log2_min_pu_size; + + for(j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++) + for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++) + tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv; + } + } + + if (current_mv.pred_flag & PF_L0) { + ref0 = refPicList[0].ref[current_mv.ref_idx[0]]; + if (!ref0) + return; + hevc_await_progress(s, ref0, ¤t_mv.mv[0], y0, nPbH); + } + if (current_mv.pred_flag & PF_L1) { + ref1 = refPicList[1].ref[current_mv.ref_idx[1]]; + if (!ref1) + return; + hevc_await_progress(s, ref1, ¤t_mv.mv[1], y0, nPbH); + } + + if (current_mv.pred_flag == PF_L0) { + int x0_c = x0 >> s->sps->hshift[1]; + int y0_c = y0 >> s->sps->vshift[1]; + int nPbW_c = nPbW >> s->sps->hshift[1]; + int nPbH_c = nPbH >> s->sps->vshift[1]; + + luma_mc_uni(s, dst0, s->frame->linesize[0], ref0->frame, + ¤t_mv.mv[0], x0, y0, nPbW, nPbH, + s->sh.luma_weight_l0[current_mv.ref_idx[0]], + s->sh.luma_offset_l0[current_mv.ref_idx[0]]); + + chroma_mc_uni(s, dst1, s->frame->linesize[1], ref0->frame->data[1], ref0->frame->linesize[1], + 0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, + s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]); + chroma_mc_uni(s, dst2, s->frame->linesize[2], ref0->frame->data[2], ref0->frame->linesize[2], + 0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, + s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1]); + } else if (current_mv.pred_flag == PF_L1) { + int x0_c = x0 >> s->sps->hshift[1]; + int y0_c = y0 >> s->sps->vshift[1]; + int nPbW_c = nPbW >> s->sps->hshift[1]; + int nPbH_c = nPbH >> s->sps->vshift[1]; + + luma_mc_uni(s, dst0, s->frame->linesize[0], ref1->frame, + ¤t_mv.mv[1], x0, y0, nPbW, nPbH, + s->sh.luma_weight_l1[current_mv.ref_idx[1]], + s->sh.luma_offset_l1[current_mv.ref_idx[1]]); + + chroma_mc_uni(s, dst1, s->frame->linesize[1], ref1->frame->data[1], ref1->frame->linesize[1], + 1, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, + s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0]); + + chroma_mc_uni(s, dst2, s->frame->linesize[2], ref1->frame->data[2], ref1->frame->linesize[2], + 1, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, + s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1]); + } else if (current_mv.pred_flag == PF_BI) { + int x0_c = x0 >> s->sps->hshift[1]; + int y0_c = y0 >> s->sps->vshift[1]; + int nPbW_c = nPbW >> s->sps->hshift[1]; + int nPbH_c = nPbH >> s->sps->vshift[1]; + + luma_mc_bi(s, dst0, s->frame->linesize[0], ref0->frame, + ¤t_mv.mv[0], x0, y0, nPbW, nPbH, + ref1->frame, ¤t_mv.mv[1], ¤t_mv); + + chroma_mc_bi(s, dst1, s->frame->linesize[1], ref0->frame, ref1->frame, + x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, 0); + + chroma_mc_bi(s, dst2, s->frame->linesize[2], ref0->frame, ref1->frame, + x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, 1); + } +} +#endif + +/** + * 8.4.1 + */ +static int luma_intra_pred_mode(HEVCContext *s, int x0, int y0, int pu_size, + int prev_intra_luma_pred_flag) +{ + HEVCLocalContext *lc = s->HEVClc; + int x_pu = x0 >> s->sps->log2_min_pu_size; + int y_pu = y0 >> s->sps->log2_min_pu_size; + int min_pu_width = s->sps->min_pu_width; + int size_in_pus = pu_size >> s->sps->log2_min_pu_size; + int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1); + int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1); + + int cand_up = (lc->ctb_up_flag || y0b) ? + s->tab_ipm[(y_pu - 1) * min_pu_width + x_pu] : INTRA_DC; + int cand_left = (lc->ctb_left_flag || x0b) ? + s->tab_ipm[y_pu * min_pu_width + x_pu - 1] : INTRA_DC; + + int y_ctb = (y0 >> (s->sps->log2_ctb_size)) << (s->sps->log2_ctb_size); + +#ifdef USE_PRED + MvField *tab_mvf = s->ref->tab_mvf; + int j; +#endif + int intra_pred_mode; + int candidate[3]; + int i; + + // intra_pred_mode prediction does not cross vertical CTB boundaries + if ((y0 - 1) < y_ctb) + cand_up = INTRA_DC; + + if (cand_left == cand_up) { + if (cand_left < 2) { + candidate[0] = INTRA_PLANAR; + candidate[1] = INTRA_DC; + candidate[2] = INTRA_ANGULAR_26; + } else { + candidate[0] = cand_left; + candidate[1] = 2 + ((cand_left - 2 - 1 + 32) & 31); + candidate[2] = 2 + ((cand_left - 2 + 1) & 31); + } + } else { + candidate[0] = cand_left; + candidate[1] = cand_up; + if (candidate[0] != INTRA_PLANAR && candidate[1] != INTRA_PLANAR) { + candidate[2] = INTRA_PLANAR; + } else if (candidate[0] != INTRA_DC && candidate[1] != INTRA_DC) { + candidate[2] = INTRA_DC; + } else { + candidate[2] = INTRA_ANGULAR_26; + } + } + + if (prev_intra_luma_pred_flag) { + intra_pred_mode = candidate[lc->pu.mpm_idx]; + } else { + if (candidate[0] > candidate[1]) + FFSWAP(uint8_t, candidate[0], candidate[1]); + if (candidate[0] > candidate[2]) + FFSWAP(uint8_t, candidate[0], candidate[2]); + if (candidate[1] > candidate[2]) + FFSWAP(uint8_t, candidate[1], candidate[2]); + + intra_pred_mode = lc->pu.rem_intra_luma_pred_mode; + for (i = 0; i < 3; i++) + if (intra_pred_mode >= candidate[i]) + intra_pred_mode++; + } + + /* write the intra prediction units into the mv array */ + if (!size_in_pus) + size_in_pus = 1; + for (i = 0; i < size_in_pus; i++) { + memset(&s->tab_ipm[(y_pu + i) * min_pu_width + x_pu], + intra_pred_mode, size_in_pus); +#ifdef USE_PRED + for (j = 0; j < size_in_pus; j++) { + tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].pred_flag = PF_INTRA; + } +#endif + } + + return intra_pred_mode; +} + +static av_always_inline void set_ct_depth(HEVCContext *s, int x0, int y0, + int log2_cb_size, int ct_depth) +{ + int length = (1 << log2_cb_size) >> s->sps->log2_min_cb_size; + int x_cb = x0 >> s->sps->log2_min_cb_size; + int y_cb = y0 >> s->sps->log2_min_cb_size; + int y; + + for (y = 0; y < length; y++) + memset(&s->tab_ct_depth[(y_cb + y) * s->sps->min_cb_width + x_cb], + ct_depth, length); +} + +static const uint8_t tab_mode_idx[] = { + 0, 1, 2, 2, 2, 2, 3, 5, 7, 8, 10, 12, 13, 15, 17, 18, 19, 20, + 21, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 29, 30, 31}; + +static void intra_prediction_unit(HEVCContext *s, int x0, int y0, + int log2_cb_size) +{ + HEVCLocalContext *lc = s->HEVClc; + static const uint8_t intra_chroma_table[4] = { 0, 26, 10, 1 }; + uint8_t prev_intra_luma_pred_flag[4]; + int split = lc->cu.part_mode == PART_NxN; + int pb_size = (1 << log2_cb_size) >> split; + int side = split + 1; + int chroma_mode; + int i, j; + + for (i = 0; i < side; i++) + for (j = 0; j < side; j++) + prev_intra_luma_pred_flag[2 * i + j] = ff_hevc_prev_intra_luma_pred_flag_decode(s); + + for (i = 0; i < side; i++) { + for (j = 0; j < side; j++) { + if (prev_intra_luma_pred_flag[2 * i + j]) + lc->pu.mpm_idx = ff_hevc_mpm_idx_decode(s); + else + lc->pu.rem_intra_luma_pred_mode = ff_hevc_rem_intra_luma_pred_mode_decode(s); + + lc->pu.intra_pred_mode[2 * i + j] = + luma_intra_pred_mode(s, x0 + pb_size * j, y0 + pb_size * i, pb_size, + prev_intra_luma_pred_flag[2 * i + j]); + } + } + + if (s->sps->chroma_format_idc == 3) { + for (i = 0; i < side; i++) { + for (j = 0; j < side; j++) { + lc->pu.chroma_mode_c[2 * i + j] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s); + if (chroma_mode != 4) { + if (lc->pu.intra_pred_mode[2 * i + j] == intra_chroma_table[chroma_mode]) + lc->pu.intra_pred_mode_c[2 * i + j] = 34; + else + lc->pu.intra_pred_mode_c[2 * i + j] = intra_chroma_table[chroma_mode]; + } else { + lc->pu.intra_pred_mode_c[2 * i + j] = lc->pu.intra_pred_mode[2 * i + j]; + } + } + } + } else if (s->sps->chroma_format_idc == 2) { + int mode_idx; + lc->pu.chroma_mode_c[0] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s); + if (chroma_mode != 4) { + if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode]) + mode_idx = 34; + else + mode_idx = intra_chroma_table[chroma_mode]; + } else { + mode_idx = lc->pu.intra_pred_mode[0]; + } + lc->pu.intra_pred_mode_c[0] = tab_mode_idx[mode_idx]; + } else if (s->sps->chroma_format_idc != 0) { + chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s); + if (chroma_mode != 4) { + if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode]) + lc->pu.intra_pred_mode_c[0] = 34; + else + lc->pu.intra_pred_mode_c[0] = intra_chroma_table[chroma_mode]; + } else { + lc->pu.intra_pred_mode_c[0] = lc->pu.intra_pred_mode[0]; + } + } +} + +static void intra_prediction_unit_default_value(HEVCContext *s, + int x0, int y0, + int log2_cb_size) +{ + HEVCLocalContext *lc = s->HEVClc; + int pb_size = 1 << log2_cb_size; + int size_in_pus = pb_size >> s->sps->log2_min_pu_size; + int min_pu_width = s->sps->min_pu_width; +#ifdef USE_PRED + MvField *tab_mvf = s->ref->tab_mvf; +#endif + int x_pu = x0 >> s->sps->log2_min_pu_size; + int y_pu = y0 >> s->sps->log2_min_pu_size; + int j, k; + + if (size_in_pus == 0) + size_in_pus = 1; + for (j = 0; j < size_in_pus; j++) + memset(&s->tab_ipm[(y_pu + j) * min_pu_width + x_pu], INTRA_DC, size_in_pus); +#ifdef USE_PRED + if (lc->cu.pred_mode == MODE_INTRA) + for (j = 0; j < size_in_pus; j++) + for (k = 0; k < size_in_pus; k++) + tab_mvf[(y_pu + j) * min_pu_width + x_pu + k].pred_flag = PF_INTRA; +#endif +} + +static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size) +{ + int cb_size = 1 << log2_cb_size; + HEVCLocalContext *lc = s->HEVClc; + int log2_min_cb_size = s->sps->log2_min_cb_size; + int length = cb_size >> log2_min_cb_size; + int min_cb_width = s->sps->min_cb_width; + int x_cb = x0 >> log2_min_cb_size; + int y_cb = y0 >> log2_min_cb_size; +#ifdef USE_PRED + int idx = log2_cb_size - 2; +#endif + int qp_block_mask = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1; + int x, y, ret; + + lc->cu.x = x0; + lc->cu.y = y0; + lc->cu.rqt_root_cbf = 1; + lc->cu.pred_mode = MODE_INTRA; + lc->cu.part_mode = PART_2Nx2N; + lc->cu.intra_split_flag = 0; + lc->cu.pcm_flag = 0; + + SAMPLE_CTB(s->skip_flag, x_cb, y_cb) = 0; + for (x = 0; x < 4; x++) + lc->pu.intra_pred_mode[x] = 1; + if (s->pps->transquant_bypass_enable_flag) { + lc->cu.cu_transquant_bypass_flag = ff_hevc_cu_transquant_bypass_flag_decode(s); + if (lc->cu.cu_transquant_bypass_flag) + set_deblocking_bypass(s, x0, y0, log2_cb_size); + } else + lc->cu.cu_transquant_bypass_flag = 0; + +#ifdef USE_PRED + if (s->sh.slice_type != I_SLICE) { + uint8_t skip_flag = ff_hevc_skip_flag_decode(s, x0, y0, x_cb, y_cb); + + x = y_cb * min_cb_width + x_cb; + for (y = 0; y < length; y++) { + memset(&s->skip_flag[x], skip_flag, length); + x += min_cb_width; + } + lc->cu.pred_mode = skip_flag ? MODE_SKIP : MODE_INTER; + } else +#endif + { + x = y_cb * min_cb_width + x_cb; + for (y = 0; y < length; y++) { + memset(&s->skip_flag[x], 0, length); + x += min_cb_width; + } + } + +#ifdef USE_PRED + if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) { + hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); + intra_prediction_unit_default_value(s, x0, y0, log2_cb_size); + + if (!s->sh.disable_deblocking_filter_flag) + ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size); + } else +#endif + { +#ifdef USE_PRED + if (s->sh.slice_type != I_SLICE) + lc->cu.pred_mode = ff_hevc_pred_mode_decode(s); +#endif + if (lc->cu.pred_mode != MODE_INTRA || + log2_cb_size == s->sps->log2_min_cb_size) { + lc->cu.part_mode = ff_hevc_part_mode_decode(s, log2_cb_size); + lc->cu.intra_split_flag = lc->cu.part_mode == PART_NxN && + lc->cu.pred_mode == MODE_INTRA; + } + + if (lc->cu.pred_mode == MODE_INTRA) { + if (lc->cu.part_mode == PART_2Nx2N && s->sps->pcm_enabled_flag && + log2_cb_size >= s->sps->pcm.log2_min_pcm_cb_size && + log2_cb_size <= s->sps->pcm.log2_max_pcm_cb_size) { + lc->cu.pcm_flag = ff_hevc_pcm_flag_decode(s); + } + if (lc->cu.pcm_flag) { + intra_prediction_unit_default_value(s, x0, y0, log2_cb_size); + ret = hls_pcm_sample(s, x0, y0, log2_cb_size); + if (s->sps->pcm.loop_filter_disable_flag) + set_deblocking_bypass(s, x0, y0, log2_cb_size); + + if (ret < 0) + return ret; + } else { + intra_prediction_unit(s, x0, y0, log2_cb_size); + } + } else { +#ifdef USE_PRED + intra_prediction_unit_default_value(s, x0, y0, log2_cb_size); + switch (lc->cu.part_mode) { + case PART_2Nx2N: + hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); + break; + case PART_2NxN: + hls_prediction_unit(s, x0, y0, cb_size, cb_size / 2, log2_cb_size, 0, idx); + hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size, cb_size / 2, log2_cb_size, 1, idx); + break; + case PART_Nx2N: + hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size, log2_cb_size, 0, idx - 1); + hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size, log2_cb_size, 1, idx - 1); + break; + case PART_2NxnU: + hls_prediction_unit(s, x0, y0, cb_size, cb_size / 4, log2_cb_size, 0, idx); + hls_prediction_unit(s, x0, y0 + cb_size / 4, cb_size, cb_size * 3 / 4, log2_cb_size, 1, idx); + break; + case PART_2NxnD: + hls_prediction_unit(s, x0, y0, cb_size, cb_size * 3 / 4, log2_cb_size, 0, idx); + hls_prediction_unit(s, x0, y0 + cb_size * 3 / 4, cb_size, cb_size / 4, log2_cb_size, 1, idx); + break; + case PART_nLx2N: + hls_prediction_unit(s, x0, y0, cb_size / 4, cb_size, log2_cb_size, 0, idx - 2); + hls_prediction_unit(s, x0 + cb_size / 4, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 1, idx - 2); + break; + case PART_nRx2N: + hls_prediction_unit(s, x0, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 0, idx - 2); + hls_prediction_unit(s, x0 + cb_size * 3 / 4, y0, cb_size / 4, cb_size, log2_cb_size, 1, idx - 2); + break; + case PART_NxN: + hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size / 2, log2_cb_size, 0, idx - 1); + hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size / 2, log2_cb_size, 1, idx - 1); + hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 2, idx - 1); + hls_prediction_unit(s, x0 + cb_size / 2, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 3, idx - 1); + break; + } +#else + abort(); +#endif + } + + if (!lc->cu.pcm_flag) { +#ifdef USE_PRED + if (lc->cu.pred_mode != MODE_INTRA && + !(lc->cu.part_mode == PART_2Nx2N && lc->pu.merge_flag)) { + lc->cu.rqt_root_cbf = ff_hevc_no_residual_syntax_flag_decode(s); + } +#endif + if (lc->cu.rqt_root_cbf) { + const static int cbf[2] = { 0 }; + lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ? + s->sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag : + s->sps->max_transform_hierarchy_depth_inter; + ret = hls_transform_tree(s, x0, y0, x0, y0, x0, y0, + log2_cb_size, + log2_cb_size, 0, 0, cbf, cbf); + if (ret < 0) + return ret; + } else { + if (!s->sh.disable_deblocking_filter_flag) + ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size); + } + } + } + + if (s->pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0) + ff_hevc_set_qPy(s, x0, y0, log2_cb_size); + + x = y_cb * min_cb_width + x_cb; + for (y = 0; y < length; y++) { + memset(&s->qp_y_tab[x], lc->qp_y, length); + x += min_cb_width; + } + + if(((x0 + (1<qPy_pred = lc->qp_y; + } + + set_ct_depth(s, x0, y0, log2_cb_size, lc->ct_depth); + + return 0; +} + +static int hls_coding_quadtree(HEVCContext *s, int x0, int y0, + int log2_cb_size, int cb_depth) +{ + HEVCLocalContext *lc = s->HEVClc; + const int cb_size = 1 << log2_cb_size; + int ret; + int qp_block_mask = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1; + int split_cu; + + lc->ct_depth = cb_depth; + if (x0 + cb_size <= s->sps->width && + y0 + cb_size <= s->sps->height && + log2_cb_size > s->sps->log2_min_cb_size) { + split_cu = ff_hevc_split_coding_unit_flag_decode(s, cb_depth, x0, y0); + } else { + split_cu = (log2_cb_size > s->sps->log2_min_cb_size); + } + if (s->pps->cu_qp_delta_enabled_flag && + log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth) { + lc->tu.is_cu_qp_delta_coded = 0; + lc->tu.cu_qp_delta = 0; + } + + if (s->sh.cu_chroma_qp_offset_enabled_flag && + log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_chroma_qp_offset_depth) { + lc->tu.is_cu_chroma_qp_offset_coded = 0; + } + + if (split_cu) { + const int cb_size_split = cb_size >> 1; + const int x1 = x0 + cb_size_split; + const int y1 = y0 + cb_size_split; + + int more_data = 0; + + more_data = hls_coding_quadtree(s, x0, y0, log2_cb_size - 1, cb_depth + 1); + if (more_data < 0) + return more_data; + + if (more_data && x1 < s->sps->width) { + more_data = hls_coding_quadtree(s, x1, y0, log2_cb_size - 1, cb_depth + 1); + if (more_data < 0) + return more_data; + } + if (more_data && y1 < s->sps->height) { + more_data = hls_coding_quadtree(s, x0, y1, log2_cb_size - 1, cb_depth + 1); + if (more_data < 0) + return more_data; + } + if (more_data && x1 < s->sps->width && + y1 < s->sps->height) { + more_data = hls_coding_quadtree(s, x1, y1, log2_cb_size - 1, cb_depth + 1); + if (more_data < 0) + return more_data; + } + + if(((x0 + (1<qPy_pred = lc->qp_y; + + if (more_data) + return ((x1 + cb_size_split) < s->sps->width || + (y1 + cb_size_split) < s->sps->height); + else + return 0; + } else { + ret = hls_coding_unit(s, x0, y0, log2_cb_size); + if (ret < 0) + return ret; + if ((!((x0 + cb_size) % + (1 << (s->sps->log2_ctb_size))) || + (x0 + cb_size >= s->sps->width)) && + (!((y0 + cb_size) % + (1 << (s->sps->log2_ctb_size))) || + (y0 + cb_size >= s->sps->height))) { + int end_of_slice_flag = ff_hevc_end_of_slice_flag_decode(s); + return !end_of_slice_flag; + } else { + return 1; + } + } + + return 0; +} + +static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb, + int ctb_addr_ts) +{ + HEVCLocalContext *lc = s->HEVClc; + int ctb_size = 1 << s->sps->log2_ctb_size; + int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts]; + int ctb_addr_in_slice = ctb_addr_rs - s->sh.slice_addr; + + s->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr; + + if (s->pps->entropy_coding_sync_enabled_flag) { + if (x_ctb == 0 && (y_ctb & (ctb_size - 1)) == 0) + lc->first_qp_group = 1; + lc->end_of_tiles_x = s->sps->width; + } else if (s->pps->tiles_enabled_flag) { + if (ctb_addr_ts && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) { + int idxX = s->pps->col_idxX[x_ctb >> s->sps->log2_ctb_size]; + lc->end_of_tiles_x = x_ctb + (s->pps->column_width[idxX] << s->sps->log2_ctb_size); + lc->first_qp_group = 1; + } + } else { + lc->end_of_tiles_x = s->sps->width; + } + + lc->end_of_tiles_y = FFMIN(y_ctb + ctb_size, s->sps->height); + + lc->boundary_flags = 0; + if (s->pps->tiles_enabled_flag) { + if (x_ctb > 0 && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - 1]]) + lc->boundary_flags |= BOUNDARY_LEFT_TILE; + if (x_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - 1]) + lc->boundary_flags |= BOUNDARY_LEFT_SLICE; + if (y_ctb > 0 && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]]) + lc->boundary_flags |= BOUNDARY_UPPER_TILE; + if (y_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - s->sps->ctb_width]) + lc->boundary_flags |= BOUNDARY_UPPER_SLICE; + } else { + if (!ctb_addr_in_slice > 0) + lc->boundary_flags |= BOUNDARY_LEFT_SLICE; + if (ctb_addr_in_slice < s->sps->ctb_width) + lc->boundary_flags |= BOUNDARY_UPPER_SLICE; + } + + lc->ctb_left_flag = ((x_ctb > 0) && (ctb_addr_in_slice > 0) && !(lc->boundary_flags & BOUNDARY_LEFT_TILE)); + lc->ctb_up_flag = ((y_ctb > 0) && (ctb_addr_in_slice >= s->sps->ctb_width) && !(lc->boundary_flags & BOUNDARY_UPPER_TILE)); + lc->ctb_up_right_flag = ((y_ctb > 0) && (ctb_addr_in_slice+1 >= s->sps->ctb_width) && (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs+1 - s->sps->ctb_width]])); + lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0) && (ctb_addr_in_slice-1 >= s->sps->ctb_width) && (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - s->sps->ctb_width]])); +} + +static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread) +{ + HEVCContext *s = avctxt->priv_data; + int ctb_size = 1 << s->sps->log2_ctb_size; + int more_data = 1; + int x_ctb = 0; + int y_ctb = 0; + int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]; + + if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) { + av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n"); + return AVERROR_INVALIDDATA; + } + + if (s->sh.dependent_slice_segment_flag) { + int prev_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1]; + if (s->tab_slice_address[prev_rs] != s->sh.slice_addr) { + av_log(s->avctx, AV_LOG_ERROR, "Previous slice segment missing\n"); + return AVERROR_INVALIDDATA; + } + } + + while (more_data && ctb_addr_ts < s->sps->ctb_size) { + int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts]; + + x_ctb = (ctb_addr_rs % ((s->sps->width + ctb_size - 1) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size; + y_ctb = (ctb_addr_rs / ((s->sps->width + ctb_size - 1) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size; + hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts); + + ff_hevc_cabac_init(s, ctb_addr_ts); + + hls_sao_param(s, x_ctb >> s->sps->log2_ctb_size, y_ctb >> s->sps->log2_ctb_size); + + s->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset; + s->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset; + s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag; + + more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0); + if (more_data < 0) { + s->tab_slice_address[ctb_addr_rs] = -1; + return more_data; + } + + + ctb_addr_ts++; + ff_hevc_save_states(s, ctb_addr_ts); + ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size); + } + + if (x_ctb + ctb_size >= s->sps->width && + y_ctb + ctb_size >= s->sps->height) + ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size); + + return ctb_addr_ts; +} + +static int hls_slice_data(HEVCContext *s) +{ + int arg[2]; + int ret[2]; + + arg[0] = 0; + arg[1] = 1; + + s->avctx->execute(s->avctx, hls_decode_entry, arg, ret , 1, sizeof(int)); + return ret[0]; +} + +#ifdef USE_FULL +static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int job, int self_id) +{ + HEVCContext *s1 = avctxt->priv_data, *s; + HEVCLocalContext *lc; + int ctb_size = 1<< s1->sps->log2_ctb_size; + int more_data = 1; + int *ctb_row_p = input_ctb_row; + int ctb_row = ctb_row_p[job]; + int ctb_addr_rs = s1->sh.slice_ctb_addr_rs + ctb_row * ((s1->sps->width + ctb_size - 1) >> s1->sps->log2_ctb_size); + int ctb_addr_ts = s1->pps->ctb_addr_rs_to_ts[ctb_addr_rs]; + int thread = ctb_row % s1->threads_number; + int ret; + + s = s1->sList[self_id]; + lc = s->HEVClc; + + if(ctb_row) { + ret = init_get_bits8(&lc->gb, s->data + s->sh.offset[ctb_row - 1], s->sh.size[ctb_row - 1]); + + if (ret < 0) + return ret; + ff_init_cabac_decoder(&lc->cc, s->data + s->sh.offset[(ctb_row)-1], s->sh.size[ctb_row - 1]); + } + + while(more_data && ctb_addr_ts < s->sps->ctb_size) { + int x_ctb = (ctb_addr_rs % s->sps->ctb_width) << s->sps->log2_ctb_size; + int y_ctb = (ctb_addr_rs / s->sps->ctb_width) << s->sps->log2_ctb_size; + + hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts); + + ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP); + + if (avpriv_atomic_int_get(&s1->wpp_err)){ + ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + return 0; + } + + ff_hevc_cabac_init(s, ctb_addr_ts); + hls_sao_param(s, x_ctb >> s->sps->log2_ctb_size, y_ctb >> s->sps->log2_ctb_size); + more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0); + + if (more_data < 0) { + s->tab_slice_address[ctb_addr_rs] = -1; + return more_data; + } + + ctb_addr_ts++; + + ff_hevc_save_states(s, ctb_addr_ts); + ff_thread_report_progress2(s->avctx, ctb_row, thread, 1); + ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size); + + if (!more_data && (x_ctb+ctb_size) < s->sps->width && ctb_row != s->sh.num_entry_point_offsets) { + avpriv_atomic_int_set(&s1->wpp_err, 1); + ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + return 0; + } + + if ((x_ctb+ctb_size) >= s->sps->width && (y_ctb+ctb_size) >= s->sps->height ) { + ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size); + ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + return ctb_addr_ts; + } + ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts]; + x_ctb+=ctb_size; + + if(x_ctb >= s->sps->width) { + break; + } + } + ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + + return 0; +} + +static int hls_slice_data_wpp(HEVCContext *s, const uint8_t *nal, int length) +{ + HEVCLocalContext *lc = s->HEVClc; + int *ret = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int)); + int *arg = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int)); + int offset; + int startheader, cmpt = 0; + int i, j, res = 0; + + + if (!s->sList[1]) { + ff_alloc_entries(s->avctx, s->sh.num_entry_point_offsets + 1); + + + for (i = 1; i < s->threads_number; i++) { + s->sList[i] = av_malloc(sizeof(HEVCContext)); + memcpy(s->sList[i], s, sizeof(HEVCContext)); + s->HEVClcList[i] = av_mallocz(sizeof(HEVCLocalContext)); + s->sList[i]->HEVClc = s->HEVClcList[i]; + } + } + + offset = (lc->gb.index >> 3); + + for (j = 0, cmpt = 0, startheader = offset + s->sh.entry_point_offset[0]; j < s->skipped_bytes; j++) { + if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) { + startheader--; + cmpt++; + } + } + + for (i = 1; i < s->sh.num_entry_point_offsets; i++) { + offset += (s->sh.entry_point_offset[i - 1] - cmpt); + for (j = 0, cmpt = 0, startheader = offset + + s->sh.entry_point_offset[i]; j < s->skipped_bytes; j++) { + if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) { + startheader--; + cmpt++; + } + } + s->sh.size[i - 1] = s->sh.entry_point_offset[i] - cmpt; + s->sh.offset[i - 1] = offset; + + } + if (s->sh.num_entry_point_offsets != 0) { + offset += s->sh.entry_point_offset[s->sh.num_entry_point_offsets - 1] - cmpt; + s->sh.size[s->sh.num_entry_point_offsets - 1] = length - offset; + s->sh.offset[s->sh.num_entry_point_offsets - 1] = offset; + + } + s->data = nal; + + for (i = 1; i < s->threads_number; i++) { + s->sList[i]->HEVClc->first_qp_group = 1; + s->sList[i]->HEVClc->qp_y = s->sList[0]->HEVClc->qp_y; + memcpy(s->sList[i], s, sizeof(HEVCContext)); + s->sList[i]->HEVClc = s->HEVClcList[i]; + } + + avpriv_atomic_int_set(&s->wpp_err, 0); + ff_reset_entries(s->avctx); + + for (i = 0; i <= s->sh.num_entry_point_offsets; i++) { + arg[i] = i; + ret[i] = 0; + } + + if (s->pps->entropy_coding_sync_enabled_flag) + s->avctx->execute2(s->avctx, (void *) hls_decode_entry_wpp, arg, ret, s->sh.num_entry_point_offsets + 1); + + for (i = 0; i <= s->sh.num_entry_point_offsets; i++) + res += ret[i]; + av_free(ret); + av_free(arg); + return res; +} +#endif + +/** + * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, + * 0 if the unit should be skipped, 1 otherwise + */ +static int hls_nal_unit(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + int nuh_layer_id; + + if (get_bits1(gb) != 0) + return AVERROR_INVALIDDATA; + + s->nal_unit_type = get_bits(gb, 6); + + nuh_layer_id = get_bits(gb, 6); + s->temporal_id = get_bits(gb, 3) - 1; + if (s->temporal_id < 0) + return AVERROR_INVALIDDATA; + + av_log(s->avctx, AV_LOG_DEBUG, + "nal_unit_type: %d, nuh_layer_id: %d, temporal_id: %d\n", + s->nal_unit_type, nuh_layer_id, s->temporal_id); + + return nuh_layer_id == 0; +} + +static int set_side_data(HEVCContext *s) +{ +#ifdef USE_FULL + AVFrame *out = s->ref->frame; + + if (s->sei_frame_packing_present && + s->frame_packing_arrangement_type >= 3 && + s->frame_packing_arrangement_type <= 5 && + s->content_interpretation_type > 0 && + s->content_interpretation_type < 3) { + AVStereo3D *stereo = av_stereo3d_create_side_data(out); + if (!stereo) + return AVERROR(ENOMEM); + + switch (s->frame_packing_arrangement_type) { + case 3: + if (s->quincunx_subsampling) + stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; + else + stereo->type = AV_STEREO3D_SIDEBYSIDE; + break; + case 4: + stereo->type = AV_STEREO3D_TOPBOTTOM; + break; + case 5: + stereo->type = AV_STEREO3D_FRAMESEQUENCE; + break; + } + + if (s->content_interpretation_type == 2) + stereo->flags = AV_STEREO3D_FLAG_INVERT; + } + + if (s->sei_display_orientation_present && + (s->sei_anticlockwise_rotation || s->sei_hflip || s->sei_vflip)) { + double angle = s->sei_anticlockwise_rotation * 360 / (double) (1 << 16); + AVFrameSideData *rotation = av_frame_new_side_data(out, + AV_FRAME_DATA_DISPLAYMATRIX, + sizeof(int32_t) * 9); + if (!rotation) + return AVERROR(ENOMEM); + + av_display_rotation_set((int32_t *)rotation->data, angle); + av_display_matrix_flip((int32_t *)rotation->data, + s->sei_hflip, s->sei_vflip); + } +#endif + return 0; +} + +static int hevc_frame_start(HEVCContext *s) +{ + HEVCLocalContext *lc = s->HEVClc; + int pic_size_in_ctb = ((s->sps->width >> s->sps->log2_min_cb_size) + 1) * + ((s->sps->height >> s->sps->log2_min_cb_size) + 1); + int ret; + + memset(s->horizontal_bs, 0, s->bs_width * s->bs_height); + memset(s->vertical_bs, 0, s->bs_width * s->bs_height); + memset(s->cbf_luma, 0, s->sps->min_tb_width * s->sps->min_tb_height); + memset(s->is_pcm, 0, (s->sps->min_pu_width + 1) * (s->sps->min_pu_height + 1)); + memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address)); + + s->is_decoded = 0; + s->first_nal_type = s->nal_unit_type; + + if (s->pps->tiles_enabled_flag) + lc->end_of_tiles_x = s->pps->column_width[0] << s->sps->log2_ctb_size; + + ret = ff_hevc_set_new_ref(s, &s->frame, s->poc); + if (ret < 0) + goto fail; + +#ifdef USE_PRED + ret = ff_hevc_frame_rps(s); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Error constructing the frame RPS.\n"); + goto fail; + } +#endif + + s->ref->frame->key_frame = IS_IRAP(s); + + ret = set_side_data(s); + if (ret < 0) + goto fail; + + s->frame->pict_type = 3 - s->sh.slice_type; + +#ifdef USE_PRED + if (!IS_IRAP(s)) + ff_hevc_bump_frame(s); +#endif + + av_frame_unref(s->output_frame); + ret = ff_hevc_output_frame(s, s->output_frame, 0); + if (ret < 0) + goto fail; + + ff_thread_finish_setup(s->avctx); + + return 0; + +fail: + if (s->ref && s->threads_type == FF_THREAD_FRAME) + ff_thread_report_progress(&s->ref->tf, INT_MAX, 0); + s->ref = NULL; + return ret; +} + +static int decode_nal_unit(HEVCContext *s, const uint8_t *nal, int length) +{ + HEVCLocalContext *lc = s->HEVClc; + GetBitContext *gb = &lc->gb; + int ctb_addr_ts, ret; + + ret = init_get_bits8(gb, nal, length); + if (ret < 0) + return ret; + + ret = hls_nal_unit(s); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", + s->nal_unit_type); + goto fail; + } else if (!ret) + return 0; + + switch (s->nal_unit_type) { +#ifdef USE_MSPS + case 48: + ret = ff_hevc_decode_nal_sps(s); + if (ret < 0) + goto fail; + break; +#else + case NAL_VPS: + ret = ff_hevc_decode_nal_vps(s); + if (ret < 0) + goto fail; + break; + case NAL_SPS: + ret = ff_hevc_decode_nal_sps(s); + if (ret < 0) + goto fail; + break; +#endif + case NAL_PPS: + ret = ff_hevc_decode_nal_pps(s); + if (ret < 0) + goto fail; + break; + case NAL_SEI_PREFIX: + case NAL_SEI_SUFFIX: + ret = ff_hevc_decode_nal_sei(s); + if (ret < 0) + goto fail; + break; + case NAL_TRAIL_R: + case NAL_TRAIL_N: + case NAL_TSA_N: + case NAL_TSA_R: + case NAL_STSA_N: + case NAL_STSA_R: + case NAL_BLA_W_LP: + case NAL_BLA_W_RADL: + case NAL_BLA_N_LP: + case NAL_IDR_W_RADL: + case NAL_IDR_N_LP: + case NAL_CRA_NUT: + case NAL_RADL_N: + case NAL_RADL_R: + case NAL_RASL_N: + case NAL_RASL_R: + ret = hls_slice_header(s); + if (ret < 0) + return ret; + + if (s->max_ra == INT_MAX) { + if (s->nal_unit_type == NAL_CRA_NUT || IS_BLA(s)) { + s->max_ra = s->poc; + } else { + if (IS_IDR(s)) + s->max_ra = INT_MIN; + } + } + + if ((s->nal_unit_type == NAL_RASL_R || s->nal_unit_type == NAL_RASL_N) && + s->poc <= s->max_ra) { + s->is_decoded = 0; + break; + } else { + if (s->nal_unit_type == NAL_RASL_R && s->poc > s->max_ra) + s->max_ra = INT_MIN; + } + + if (s->sh.first_slice_in_pic_flag) { + ret = hevc_frame_start(s); + if (ret < 0) + return ret; + } else if (!s->ref) { + av_log(s->avctx, AV_LOG_ERROR, "First slice in a frame missing.\n"); + goto fail; + } + + if (s->nal_unit_type != s->first_nal_type) { + av_log(s->avctx, AV_LOG_ERROR, + "Non-matching NAL types of the VCL NALUs: %d %d\n", + s->first_nal_type, s->nal_unit_type); + return AVERROR_INVALIDDATA; + } + +#ifdef USE_PRED + if (!s->sh.dependent_slice_segment_flag && + s->sh.slice_type != I_SLICE) { + ret = ff_hevc_slice_rpl(s); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, + "Error constructing the reference lists for the current slice.\n"); + goto fail; + } + } +#endif + +#ifdef USE_FULL + if (s->threads_number > 1 && s->sh.num_entry_point_offsets > 0) + ctb_addr_ts = hls_slice_data_wpp(s, nal, length); + else +#endif + ctb_addr_ts = hls_slice_data(s); + if (ctb_addr_ts >= (s->sps->ctb_width * s->sps->ctb_height)) { + s->is_decoded = 1; + } + + if (ctb_addr_ts < 0) { + ret = ctb_addr_ts; + goto fail; + } + break; + case NAL_EOS_NUT: + case NAL_EOB_NUT: + s->seq_decode = (s->seq_decode + 1) & 0xff; + s->max_ra = INT_MAX; + break; + case NAL_AUD: + case NAL_FD_NUT: + break; + default: + av_log(s->avctx, AV_LOG_INFO, + "Skipping NAL unit %d\n", s->nal_unit_type); + } + + return 0; +fail: + if (s->avctx->err_recognition & AV_EF_EXPLODE) + return ret; + return 0; +} + +/* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication + * between these functions would be nice. */ +int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, + HEVCNAL *nal) +{ + int i, si, di; + uint8_t *dst; + + s->skipped_bytes = 0; +#define STARTCODE_TEST \ + if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \ + if (src[i + 2] != 3) { \ + /* startcode, so we must be past the end */ \ + length = i; \ + } \ + break; \ + } +#if HAVE_FAST_UNALIGNED +#define FIND_FIRST_ZERO \ + if (i > 0 && !src[i]) \ + i--; \ + while (src[i]) \ + i++ +#if HAVE_FAST_64BIT + for (i = 0; i + 1 < length; i += 9) { + if (!((~AV_RN64A(src + i) & + (AV_RN64A(src + i) - 0x0100010001000101ULL)) & + 0x8000800080008080ULL)) + continue; + FIND_FIRST_ZERO; + STARTCODE_TEST; + i -= 7; + } +#else + for (i = 0; i + 1 < length; i += 5) { + if (!((~AV_RN32A(src + i) & + (AV_RN32A(src + i) - 0x01000101U)) & + 0x80008080U)) + continue; + FIND_FIRST_ZERO; + STARTCODE_TEST; + i -= 3; + } +#endif /* HAVE_FAST_64BIT */ +#else + for (i = 0; i + 1 < length; i += 2) { + if (src[i]) + continue; + if (i > 0 && src[i - 1] == 0) + i--; + STARTCODE_TEST; + } +#endif /* HAVE_FAST_UNALIGNED */ + + if (i >= length - 1) { // no escaped 0 + nal->data = src; + nal->size = length; + return length; + } + + av_fast_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, + length + FF_INPUT_BUFFER_PADDING_SIZE); + if (!nal->rbsp_buffer) + return AVERROR(ENOMEM); + + dst = nal->rbsp_buffer; + + memcpy(dst, src, i); + si = di = i; + while (si + 2 < length) { + // remove escapes (very rare 1:2^22) + if (src[si + 2] > 3) { + dst[di++] = src[si++]; + dst[di++] = src[si++]; + } else if (src[si] == 0 && src[si + 1] == 0) { + if (src[si + 2] == 3) { // escape + dst[di++] = 0; + dst[di++] = 0; + si += 3; + + s->skipped_bytes++; + if (s->skipped_bytes_pos_size < s->skipped_bytes) { + s->skipped_bytes_pos_size *= 2; + av_reallocp_array(&s->skipped_bytes_pos, + s->skipped_bytes_pos_size, + sizeof(*s->skipped_bytes_pos)); + if (!s->skipped_bytes_pos) + return AVERROR(ENOMEM); + } + if (s->skipped_bytes_pos) + s->skipped_bytes_pos[s->skipped_bytes-1] = di - 1; + continue; + } else // next start code + goto nsc; + } + + dst[di++] = src[si++]; + } + while (si < length) + dst[di++] = src[si++]; + +nsc: + memset(dst + di, 0, FF_INPUT_BUFFER_PADDING_SIZE); + + nal->data = dst; + nal->size = di; + return si; +} + +static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) +{ + int i, consumed, ret = 0; + + s->ref = NULL; + s->last_eos = s->eos; + s->eos = 0; + + /* split the input packet into NAL units, so we know the upper bound on the + * number of slices in the frame */ + s->nb_nals = 0; + while (length >= 4) { + HEVCNAL *nal; + int extract_length = 0; + + if (s->is_nalff) { + int i; + for (i = 0; i < s->nal_length_size; i++) + extract_length = (extract_length << 8) | buf[i]; + buf += s->nal_length_size; + length -= s->nal_length_size; + + if (extract_length > length) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit size.\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + } else { + /* search start code */ + while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { + ++buf; + --length; + if (length < 4) { + av_log(s->avctx, AV_LOG_ERROR, "No start code is found.\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + } + + buf += 3; + length -= 3; + } + + if (!s->is_nalff) + extract_length = length; + + if (s->nals_allocated < s->nb_nals + 1) { + int new_size = s->nals_allocated + 1; + HEVCNAL *tmp = av_realloc_array(s->nals, new_size, sizeof(*tmp)); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + s->nals = tmp; + memset(s->nals + s->nals_allocated, 0, + (new_size - s->nals_allocated) * sizeof(*tmp)); + av_reallocp_array(&s->skipped_bytes_nal, new_size, sizeof(*s->skipped_bytes_nal)); + av_reallocp_array(&s->skipped_bytes_pos_size_nal, new_size, sizeof(*s->skipped_bytes_pos_size_nal)); + av_reallocp_array(&s->skipped_bytes_pos_nal, new_size, sizeof(*s->skipped_bytes_pos_nal)); + s->skipped_bytes_pos_size_nal[s->nals_allocated] = 1024; // initial buffer size + s->skipped_bytes_pos_nal[s->nals_allocated] = av_malloc_array(s->skipped_bytes_pos_size_nal[s->nals_allocated], sizeof(*s->skipped_bytes_pos)); + s->nals_allocated = new_size; + } + s->skipped_bytes_pos_size = s->skipped_bytes_pos_size_nal[s->nb_nals]; + s->skipped_bytes_pos = s->skipped_bytes_pos_nal[s->nb_nals]; + nal = &s->nals[s->nb_nals]; + + consumed = ff_hevc_extract_rbsp(s, buf, extract_length, nal); + + s->skipped_bytes_nal[s->nb_nals] = s->skipped_bytes; + s->skipped_bytes_pos_size_nal[s->nb_nals] = s->skipped_bytes_pos_size; + s->skipped_bytes_pos_nal[s->nb_nals++] = s->skipped_bytes_pos; + + + if (consumed < 0) { + ret = consumed; + goto fail; + } + + ret = init_get_bits8(&s->HEVClc->gb, nal->data, nal->size); + if (ret < 0) + goto fail; + hls_nal_unit(s); + + if (s->nal_unit_type == NAL_EOB_NUT || + s->nal_unit_type == NAL_EOS_NUT) + s->eos = 1; + + buf += consumed; + length -= consumed; + } + + /* parse the NAL units */ + for (i = 0; i < s->nb_nals; i++) { + int ret; + s->skipped_bytes = s->skipped_bytes_nal[i]; + s->skipped_bytes_pos = s->skipped_bytes_pos_nal[i]; + + ret = decode_nal_unit(s, s->nals[i].data, s->nals[i].size); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, + "Error parsing NAL unit #%d.\n", i); + goto fail; + } + } + +fail: + if (s->ref && s->threads_type == FF_THREAD_FRAME) + ff_thread_report_progress(&s->ref->tf, INT_MAX, 0); + + return ret; +} + +#ifdef USE_MD5 +static void print_md5(void *log_ctx, int level, uint8_t md5[16]) +{ + int i; + for (i = 0; i < 16; i++) + av_log(log_ctx, level, "%02"PRIx8, md5[i]); +} + +static int verify_md5(HEVCContext *s, AVFrame *frame) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int pixel_shift; + int i, j; + + if (!desc) + return AVERROR(EINVAL); + +#ifdef USE_VAR_BIT_DEPTH + pixel_shift = s->sps->bit_depth > 8; +#else + pixel_shift = desc->comp[0].depth_minus1 > 7; +#endif + + av_log(s->avctx, AV_LOG_DEBUG, "Verifying checksum for frame with POC %d: ", + s->poc); + + /* the checksums are LE, so we have to byteswap for >8bpp formats + * on BE arches */ +#if HAVE_BIGENDIAN + if (pixel_shift && !s->checksum_buf) { + av_fast_malloc(&s->checksum_buf, &s->checksum_buf_size, + FFMAX3(frame->linesize[0], frame->linesize[1], + frame->linesize[2])); + if (!s->checksum_buf) + return AVERROR(ENOMEM); + } +#endif +#ifdef USE_VAR_BIT_DEPTH + if (pixel_shift == 0) { + av_fast_malloc(&s->checksum_buf, &s->checksum_buf_size, + FFMAX3(frame->linesize[0], frame->linesize[1], + frame->linesize[2])); + if (!s->checksum_buf) + return AVERROR(ENOMEM); + } +#endif + + for (i = 0; frame->data[i]; i++) { + int width = s->avctx->coded_width; + int height = s->avctx->coded_height; + int w = (i == 1 || i == 2) ? (width >> desc->log2_chroma_w) : width; + int h = (i == 1 || i == 2) ? (height >> desc->log2_chroma_h) : height; + uint8_t md5[16]; + + av_md5_init(s->md5_ctx); + for (j = 0; j < h; j++) { + const uint8_t *src = frame->data[i] + j * frame->linesize[i]; +#if HAVE_BIGENDIAN + if (pixel_shift) { + s->bdsp.bswap16_buf((uint16_t *) s->checksum_buf, + (const uint16_t *) src, w); + src = s->checksum_buf; + } +#endif +#ifdef USE_VAR_BIT_DEPTH + /* convert from 16 to 8 bits */ + if (pixel_shift == 0) { + int j; + for(j = 0; j < w; j++) + s->checksum_buf[j] = ((uint16_t *)src)[j]; + src = s->checksum_buf; + } +#endif + av_md5_update(s->md5_ctx, src, w << pixel_shift); + } + av_md5_final(s->md5_ctx, md5); + + if (!memcmp(md5, s->md5[i], 16)) { + av_log (s->avctx, AV_LOG_DEBUG, "plane %d - correct ", i); + print_md5(s->avctx, AV_LOG_DEBUG, md5); + av_log (s->avctx, AV_LOG_DEBUG, "; "); + } else { + av_log (s->avctx, AV_LOG_ERROR, "mismatching checksum of plane %d - ", i); + print_md5(s->avctx, AV_LOG_ERROR, md5); + av_log (s->avctx, AV_LOG_ERROR, " != "); + print_md5(s->avctx, AV_LOG_ERROR, s->md5[i]); + av_log (s->avctx, AV_LOG_ERROR, "\n"); + return AVERROR_INVALIDDATA; + } + } + + av_log(s->avctx, AV_LOG_DEBUG, "\n"); + return 0; +} +#endif + +static int hevc_decode_frame(AVCodecContext *avctx, void *data, int *got_output, + AVPacket *avpkt) +{ + int ret; + HEVCContext *s = avctx->priv_data; + + if (!avpkt->size) { + ret = ff_hevc_output_frame(s, data, 1); + if (ret < 0) + return ret; + + *got_output = ret; + return 0; + } + + s->ref = NULL; + ret = decode_nal_units(s, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + +#ifdef USE_MD5 + /* verify the SEI checksum */ + if (avctx->err_recognition & AV_EF_CRCCHECK && s->is_decoded && + s->is_md5) { + ret = verify_md5(s, s->ref->frame); + if (ret < 0 && avctx->err_recognition & AV_EF_EXPLODE) { + ff_hevc_unref_frame(s, s->ref, ~0); + return ret; + } + } + s->is_md5 = 0; +#endif + + if (s->is_decoded) { + av_log(avctx, AV_LOG_DEBUG, "Decoded frame with POC %d.\n", s->poc); + s->is_decoded = 0; + } + + if (s->output_frame->buf[0]) { + av_frame_move_ref(data, s->output_frame); + *got_output = 1; + } + + return avpkt->size; +} + +#ifdef USE_FULL +static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src) +{ + int ret; + + ret = ff_thread_ref_frame(&dst->tf, &src->tf); + if (ret < 0) + return ret; + + dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf); + if (!dst->tab_mvf_buf) + goto fail; + dst->tab_mvf = src->tab_mvf; + + dst->rpl_tab_buf = av_buffer_ref(src->rpl_tab_buf); + if (!dst->rpl_tab_buf) + goto fail; + dst->rpl_tab = src->rpl_tab; + + dst->rpl_buf = av_buffer_ref(src->rpl_buf); + if (!dst->rpl_buf) + goto fail; + + dst->poc = src->poc; + dst->ctb_count = src->ctb_count; + dst->window = src->window; + dst->flags = src->flags; + dst->sequence = src->sequence; + + return 0; +fail: + ff_hevc_unref_frame(s, dst, ~0); + return AVERROR(ENOMEM); +} +#endif + +static av_cold int hevc_decode_free(AVCodecContext *avctx) +{ + HEVCContext *s = avctx->priv_data; + int i; + + pic_arrays_free(s); + +#ifdef USE_MD5 + av_freep(&s->md5_ctx); + av_freep(&s->checksum_buf); +#endif + + for(i=0; i < s->nals_allocated; i++) { + av_freep(&s->skipped_bytes_pos_nal[i]); + } + av_freep(&s->skipped_bytes_pos_size_nal); + av_freep(&s->skipped_bytes_nal); + av_freep(&s->skipped_bytes_pos_nal); + + av_freep(&s->cabac_state); + +#ifdef USE_SAO_SMALL_BUFFER + av_freep(&s->sao_pixel_buffer); + for(i = 0; i < 3; i++) { + av_freep(&s->sao_pixel_buffer_h[i]); + av_freep(&s->sao_pixel_buffer_v[i]); + } +#else + av_frame_free(&s->tmp_frame); +#endif + av_frame_free(&s->output_frame); + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + ff_hevc_unref_frame(s, &s->DPB[i], ~0); + av_frame_free(&s->DPB[i].frame); + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++) + av_buffer_unref(&s->vps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) + av_buffer_unref(&s->sps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) + av_buffer_unref(&s->pps_list[i]); + s->sps = NULL; + s->pps = NULL; + s->vps = NULL; + + av_buffer_unref(&s->current_sps); + + av_freep(&s->sh.entry_point_offset); + av_freep(&s->sh.offset); + av_freep(&s->sh.size); + + for (i = 1; i < s->threads_number; i++) { + HEVCLocalContext *lc = s->HEVClcList[i]; + if (lc) { + av_freep(&s->HEVClcList[i]); + av_freep(&s->sList[i]); + } + } + if (s->HEVClc == s->HEVClcList[0]) + s->HEVClc = NULL; + av_freep(&s->HEVClcList[0]); + + for (i = 0; i < s->nals_allocated; i++) + av_freep(&s->nals[i].rbsp_buffer); + av_freep(&s->nals); + s->nals_allocated = 0; + + return 0; +} + +static av_cold int hevc_init_context(AVCodecContext *avctx) +{ + HEVCContext *s = avctx->priv_data; + int i; + + s->avctx = avctx; + + s->HEVClc = av_mallocz(sizeof(HEVCLocalContext)); + if (!s->HEVClc) + goto fail; + s->HEVClcList[0] = s->HEVClc; + s->sList[0] = s; + + s->cabac_state = av_malloc(HEVC_CONTEXTS); + if (!s->cabac_state) + goto fail; + +#ifndef USE_SAO_SMALL_BUFFER + s->tmp_frame = av_frame_alloc(); + if (!s->tmp_frame) + goto fail; +#endif + + s->output_frame = av_frame_alloc(); + if (!s->output_frame) + goto fail; + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + s->DPB[i].frame = av_frame_alloc(); + if (!s->DPB[i].frame) + goto fail; + s->DPB[i].tf.f = s->DPB[i].frame; + } + + s->max_ra = INT_MAX; + +#ifdef USE_MD5 + s->md5_ctx = av_md5_alloc(); + if (!s->md5_ctx) + goto fail; +#endif + +#if HAVE_BIGENDIAN + ff_bswapdsp_init(&s->bdsp); +#endif + + s->context_initialized = 1; + s->eos = 0; + + return 0; + +fail: + hevc_decode_free(avctx); + return AVERROR(ENOMEM); +} + +#ifdef USE_FULL +static int hevc_update_thread_context(AVCodecContext *dst, + const AVCodecContext *src) +{ + HEVCContext *s = dst->priv_data; + HEVCContext *s0 = src->priv_data; + int i, ret; + + if (!s->context_initialized) { + ret = hevc_init_context(dst); + if (ret < 0) + return ret; + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + ff_hevc_unref_frame(s, &s->DPB[i], ~0); + if (s0->DPB[i].frame->buf[0]) { + ret = hevc_ref_frame(s, &s->DPB[i], &s0->DPB[i]); + if (ret < 0) + return ret; + } + } + + if (s->sps != s0->sps) + s->sps = NULL; + for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++) { + av_buffer_unref(&s->vps_list[i]); + if (s0->vps_list[i]) { + s->vps_list[i] = av_buffer_ref(s0->vps_list[i]); + if (!s->vps_list[i]) + return AVERROR(ENOMEM); + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) { + av_buffer_unref(&s->sps_list[i]); + if (s0->sps_list[i]) { + s->sps_list[i] = av_buffer_ref(s0->sps_list[i]); + if (!s->sps_list[i]) + return AVERROR(ENOMEM); + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) { + av_buffer_unref(&s->pps_list[i]); + if (s0->pps_list[i]) { + s->pps_list[i] = av_buffer_ref(s0->pps_list[i]); + if (!s->pps_list[i]) + return AVERROR(ENOMEM); + } + } + + av_buffer_unref(&s->current_sps); + if (s0->current_sps) { + s->current_sps = av_buffer_ref(s0->current_sps); + if (!s->current_sps) + return AVERROR(ENOMEM); + } + + if (s->sps != s0->sps) + if ((ret = set_sps(s, s0->sps)) < 0) + return ret; + + s->seq_decode = s0->seq_decode; + s->seq_output = s0->seq_output; + s->pocTid0 = s0->pocTid0; + s->max_ra = s0->max_ra; + s->eos = s0->eos; + + s->is_nalff = s0->is_nalff; + s->nal_length_size = s0->nal_length_size; + + s->threads_number = s0->threads_number; + s->threads_type = s0->threads_type; + + if (s0->eos) { + s->seq_decode = (s->seq_decode + 1) & 0xff; + s->max_ra = INT_MAX; + } + + return 0; +} + +static int hevc_decode_extradata(HEVCContext *s) +{ + AVCodecContext *avctx = s->avctx; + GetByteContext gb; + int ret; + + bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); + + if (avctx->extradata_size > 3 && + (avctx->extradata[0] || avctx->extradata[1] || + avctx->extradata[2] > 1)) { + /* It seems the extradata is encoded as hvcC format. + * Temporarily, we support configurationVersion==0 until 14496-15 3rd + * is finalized. When finalized, configurationVersion will be 1 and we + * can recognize hvcC by checking if avctx->extradata[0]==1 or not. */ + int i, j, num_arrays, nal_len_size; + + s->is_nalff = 1; + + bytestream2_skip(&gb, 21); + nal_len_size = (bytestream2_get_byte(&gb) & 3) + 1; + num_arrays = bytestream2_get_byte(&gb); + + /* nal units in the hvcC always have length coded with 2 bytes, + * so put a fake nal_length_size = 2 while parsing them */ + s->nal_length_size = 2; + + /* Decode nal units from hvcC. */ + for (i = 0; i < num_arrays; i++) { + int type = bytestream2_get_byte(&gb) & 0x3f; + int cnt = bytestream2_get_be16(&gb); + + for (j = 0; j < cnt; j++) { + // +2 for the nal size field + int nalsize = bytestream2_peek_be16(&gb) + 2; + if (bytestream2_get_bytes_left(&gb) < nalsize) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid NAL unit size in extradata.\n"); + return AVERROR_INVALIDDATA; + } + + ret = decode_nal_units(s, gb.buffer, nalsize); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Decoding nal unit %d %d from hvcC failed\n", + type, i); + return ret; + } + bytestream2_skip(&gb, nalsize); + } + } + + /* Now store right nal length size, that will be used to parse + * all other nals */ + s->nal_length_size = nal_len_size; + } else { + s->is_nalff = 0; + ret = decode_nal_units(s, avctx->extradata, avctx->extradata_size); + if (ret < 0) + return ret; + } + return 0; +} +#endif + +static av_cold int hevc_decode_init(AVCodecContext *avctx) +{ + HEVCContext *s = avctx->priv_data; + int ret; + + ff_init_cabac_states(); +#ifdef CONFIG_SMALL + hevc_transform_init(); +#endif + +#ifdef USE_FULL + avctx->internal->allocate_progress = 1; +#endif + + ret = hevc_init_context(avctx); + if (ret < 0) + return ret; + + s->enable_parallel_tiles = 0; + s->picture_struct = 0; + + if(avctx->active_thread_type & FF_THREAD_SLICE) + s->threads_number = avctx->thread_count; + else + s->threads_number = 1; + +#ifdef USE_FULL + if (avctx->extradata_size > 0 && avctx->extradata) { + ret = hevc_decode_extradata(s); + if (ret < 0) { + hevc_decode_free(avctx); + return ret; + } + } +#endif + if((avctx->active_thread_type & FF_THREAD_FRAME) && avctx->thread_count > 1) + s->threads_type = FF_THREAD_FRAME; + else + s->threads_type = FF_THREAD_SLICE; + + return 0; +} + +#ifdef USE_FULL +static av_cold int hevc_init_thread_copy(AVCodecContext *avctx) +{ + HEVCContext *s = avctx->priv_data; + int ret; + + memset(s, 0, sizeof(*s)); + + ret = hevc_init_context(avctx); + if (ret < 0) + return ret; + + return 0; +} +#endif + +static void hevc_decode_flush(AVCodecContext *avctx) +{ + HEVCContext *s = avctx->priv_data; + ff_hevc_flush_dpb(s); + s->max_ra = INT_MAX; +} + +#define OFFSET(x) offsetof(HEVCContext, x) +#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) + +#if 0 +static const AVProfile profiles[] = { + { FF_PROFILE_HEVC_MAIN, "Main" }, + { FF_PROFILE_HEVC_MAIN_10, "Main 10" }, + { FF_PROFILE_HEVC_MAIN_STILL_PICTURE, "Main Still Picture" }, + { FF_PROFILE_HEVC_REXT, "Rext" }, + { FF_PROFILE_UNKNOWN }, +}; + +static const AVOption options[] = { + { "apply_defdispwin", "Apply default display window from VUI", OFFSET(apply_defdispwin), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR }, + { "strict-displaywin", "stricly apply default display window size", OFFSET(apply_defdispwin), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR }, + { NULL }, +}; + +static const AVClass hevc_decoder_class = { + .class_name = "HEVC decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; +#endif + +AVCodec ff_hevc_decoder = { + .name = "hevc", + .long_name = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(HEVCContext), + // .priv_class = &hevc_decoder_class, + .init = hevc_decode_init, + .close = hevc_decode_free, + .decode = hevc_decode_frame, + .flush = hevc_decode_flush, + // .update_thread_context = hevc_update_thread_context, + // .init_thread_copy = hevc_init_thread_copy, + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | + CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS, + // .profiles = NULL_IF_CONFIG_SMALL(profiles), +}; diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h new file mode 100644 index 0000000..39a3009 --- /dev/null +++ b/libavcodec/hevc.h @@ -0,0 +1,1075 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HEVC_H +#define AVCODEC_HEVC_H + +#include "libavutil/buffer.h" +#include "libavutil/md5.h" + +#include "avcodec.h" +#include "bswapdsp.h" +#include "cabac.h" +#include "get_bits.h" +#include "hevcdsp.h" +#include "hevcpred.h" +#include "internal.h" +#include "thread.h" +#include "videodsp.h" + +#define MAX_DPB_SIZE 16 // A.4.1 +#define MAX_REFS 16 + +#define MAX_NB_THREADS 16 +#define SHIFT_CTB_WPP 2 + +/** + * 7.4.2.1 + */ +#define MAX_SUB_LAYERS 7 +#ifdef USE_MSPS +#define MAX_VPS_COUNT 16 +#define MAX_SPS_COUNT 32 +#define MAX_DPB_COUNT 1 +#else +#define MAX_VPS_COUNT 1 +#define MAX_SPS_COUNT 1 +#define MAX_DPB_COUNT 32 +#endif +#define MAX_PPS_COUNT 256 +#define MAX_SHORT_TERM_RPS_COUNT 64 +#define MAX_CU_SIZE 128 + +//TODO: check if this is really the maximum +#define MAX_TRANSFORM_DEPTH 5 + +#define MAX_TB_SIZE 32 +#define MAX_LOG2_CTB_SIZE 6 +#define MAX_QP 51 +#define DEFAULT_INTRA_TC_OFFSET 2 + +#define HEVC_CONTEXTS 199 + +#define MRG_MAX_NUM_CANDS 5 + +#define L0 0 +#define L1 1 + +#define EPEL_EXTRA_BEFORE 1 +#define EPEL_EXTRA_AFTER 2 +#define EPEL_EXTRA 3 +#define QPEL_EXTRA_BEFORE 3 +#define QPEL_EXTRA_AFTER 4 +#define QPEL_EXTRA 7 + +#define EDGE_EMU_BUFFER_STRIDE 80 + +/** + * Value of the luma sample at position (x, y) in the 2D array tab. + */ +#define SAMPLE(tab, x, y) ((tab)[(y) * s->sps->width + (x)]) +#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * min_cb_width + (x)]) + +#define IS_IDR(s) ((s)->nal_unit_type == NAL_IDR_W_RADL || (s)->nal_unit_type == NAL_IDR_N_LP) +#define IS_BLA(s) ((s)->nal_unit_type == NAL_BLA_W_RADL || (s)->nal_unit_type == NAL_BLA_W_LP || \ + (s)->nal_unit_type == NAL_BLA_N_LP) +#define IS_IRAP(s) ((s)->nal_unit_type >= 16 && (s)->nal_unit_type <= 23) + +/** + * Table 7-3: NAL unit type codes + */ +enum NALUnitType { + NAL_TRAIL_N = 0, + NAL_TRAIL_R = 1, + NAL_TSA_N = 2, + NAL_TSA_R = 3, + NAL_STSA_N = 4, + NAL_STSA_R = 5, + NAL_RADL_N = 6, + NAL_RADL_R = 7, + NAL_RASL_N = 8, + NAL_RASL_R = 9, + NAL_BLA_W_LP = 16, + NAL_BLA_W_RADL = 17, + NAL_BLA_N_LP = 18, + NAL_IDR_W_RADL = 19, + NAL_IDR_N_LP = 20, + NAL_CRA_NUT = 21, + NAL_VPS = 32, + NAL_SPS = 33, + NAL_PPS = 34, + NAL_AUD = 35, + NAL_EOS_NUT = 36, + NAL_EOB_NUT = 37, + NAL_FD_NUT = 38, + NAL_SEI_PREFIX = 39, + NAL_SEI_SUFFIX = 40, +}; + +enum RPSType { + ST_CURR_BEF = 0, + ST_CURR_AFT, + ST_FOLL, + LT_CURR, + LT_FOLL, + NB_RPS_TYPE, +}; + +enum SliceType { + B_SLICE = 0, + P_SLICE = 1, + I_SLICE = 2, +}; + +enum SyntaxElement { + SAO_MERGE_FLAG = 0, + SAO_TYPE_IDX, + SAO_EO_CLASS, + SAO_BAND_POSITION, + SAO_OFFSET_ABS, + SAO_OFFSET_SIGN, + END_OF_SLICE_FLAG, + SPLIT_CODING_UNIT_FLAG, + CU_TRANSQUANT_BYPASS_FLAG, + SKIP_FLAG, + CU_QP_DELTA, + PRED_MODE_FLAG, + PART_MODE, + PCM_FLAG, + PREV_INTRA_LUMA_PRED_FLAG, + MPM_IDX, + REM_INTRA_LUMA_PRED_MODE, + INTRA_CHROMA_PRED_MODE, + MERGE_FLAG, + MERGE_IDX, + INTER_PRED_IDC, + REF_IDX_L0, + REF_IDX_L1, + ABS_MVD_GREATER0_FLAG, + ABS_MVD_GREATER1_FLAG, + ABS_MVD_MINUS2, + MVD_SIGN_FLAG, + MVP_LX_FLAG, + NO_RESIDUAL_DATA_FLAG, + SPLIT_TRANSFORM_FLAG, + CBF_LUMA, + CBF_CB_CR, + TRANSFORM_SKIP_FLAG, + EXPLICIT_RDPCM_FLAG, + EXPLICIT_RDPCM_DIR_FLAG, + LAST_SIGNIFICANT_COEFF_X_PREFIX, + LAST_SIGNIFICANT_COEFF_Y_PREFIX, + LAST_SIGNIFICANT_COEFF_X_SUFFIX, + LAST_SIGNIFICANT_COEFF_Y_SUFFIX, + SIGNIFICANT_COEFF_GROUP_FLAG, + SIGNIFICANT_COEFF_FLAG, + COEFF_ABS_LEVEL_GREATER1_FLAG, + COEFF_ABS_LEVEL_GREATER2_FLAG, + COEFF_ABS_LEVEL_REMAINING, + COEFF_SIGN_FLAG, + LOG2_RES_SCALE_ABS, + RES_SCALE_SIGN_FLAG, + CU_CHROMA_QP_OFFSET_FLAG, + CU_CHROMA_QP_OFFSET_IDX, +}; + +enum PartMode { + PART_2Nx2N = 0, + PART_2NxN = 1, + PART_Nx2N = 2, + PART_NxN = 3, + PART_2NxnU = 4, + PART_2NxnD = 5, + PART_nLx2N = 6, + PART_nRx2N = 7, +}; + +enum PredMode { + MODE_INTER = 0, + MODE_INTRA, + MODE_SKIP, +}; + +enum InterPredIdc { + PRED_L0 = 0, + PRED_L1, + PRED_BI, +}; + +enum PredFlag { + PF_INTRA = 0, + PF_L0, + PF_L1, + PF_BI, +}; + +enum IntraPredMode { + INTRA_PLANAR = 0, + INTRA_DC, + INTRA_ANGULAR_2, + INTRA_ANGULAR_3, + INTRA_ANGULAR_4, + INTRA_ANGULAR_5, + INTRA_ANGULAR_6, + INTRA_ANGULAR_7, + INTRA_ANGULAR_8, + INTRA_ANGULAR_9, + INTRA_ANGULAR_10, + INTRA_ANGULAR_11, + INTRA_ANGULAR_12, + INTRA_ANGULAR_13, + INTRA_ANGULAR_14, + INTRA_ANGULAR_15, + INTRA_ANGULAR_16, + INTRA_ANGULAR_17, + INTRA_ANGULAR_18, + INTRA_ANGULAR_19, + INTRA_ANGULAR_20, + INTRA_ANGULAR_21, + INTRA_ANGULAR_22, + INTRA_ANGULAR_23, + INTRA_ANGULAR_24, + INTRA_ANGULAR_25, + INTRA_ANGULAR_26, + INTRA_ANGULAR_27, + INTRA_ANGULAR_28, + INTRA_ANGULAR_29, + INTRA_ANGULAR_30, + INTRA_ANGULAR_31, + INTRA_ANGULAR_32, + INTRA_ANGULAR_33, + INTRA_ANGULAR_34, +}; + +enum SAOType { + SAO_NOT_APPLIED = 0, + SAO_BAND, + SAO_EDGE, + SAO_APPLIED +}; + +enum SAOEOClass { + SAO_EO_HORIZ = 0, + SAO_EO_VERT, + SAO_EO_135D, + SAO_EO_45D, +}; + +enum ScanType { + SCAN_DIAG = 0, + SCAN_HORIZ, + SCAN_VERT, +}; + +typedef struct ShortTermRPS { + unsigned int num_negative_pics; + int num_delta_pocs; + int32_t delta_poc[32]; + uint8_t used[32]; +} ShortTermRPS; + +typedef struct LongTermRPS { + int poc[32]; + uint8_t used[32]; + uint8_t nb_refs; +} LongTermRPS; + +typedef struct RefPicList { + struct HEVCFrame *ref[MAX_REFS]; + int list[MAX_REFS]; + int isLongTerm[MAX_REFS]; + int nb_refs; +} RefPicList; + +typedef struct RefPicListTab { + RefPicList refPicList[2]; +} RefPicListTab; + +typedef struct HEVCWindow { + int left_offset; + int right_offset; + int top_offset; + int bottom_offset; +} HEVCWindow; + +typedef struct VUI { + AVRational sar; + + 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; + uint8_t colour_primaries; + uint8_t transfer_characteristic; + uint8_t matrix_coeffs; + + int chroma_loc_info_present_flag; + int chroma_sample_loc_type_top_field; + int chroma_sample_loc_type_bottom_field; + int neutra_chroma_indication_flag; + + int field_seq_flag; + int frame_field_info_present_flag; + + int default_display_window_flag; + HEVCWindow def_disp_win; + + int vui_timing_info_present_flag; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + int vui_poc_proportional_to_timing_flag; + int vui_num_ticks_poc_diff_one_minus1; + int vui_hrd_parameters_present_flag; + + int bitstream_restriction_flag; + int tiles_fixed_structure_flag; + int motion_vectors_over_pic_boundaries_flag; + int restricted_ref_pic_lists_flag; + int min_spatial_segmentation_idc; + int max_bytes_per_pic_denom; + int max_bits_per_min_cu_denom; + int log2_max_mv_length_horizontal; + int log2_max_mv_length_vertical; +} VUI; + +typedef struct PTLCommon { + uint8_t profile_space; + uint8_t tier_flag; + uint8_t profile_idc; + uint8_t profile_compatibility_flag[32]; + uint8_t level_idc; + uint8_t progressive_source_flag; + uint8_t interlaced_source_flag; + uint8_t non_packed_constraint_flag; + uint8_t frame_only_constraint_flag; +} PTLCommon; + +typedef struct PTL { + PTLCommon general_ptl; + PTLCommon sub_layer_ptl[MAX_SUB_LAYERS]; + + uint8_t sub_layer_profile_present_flag[MAX_SUB_LAYERS]; + uint8_t sub_layer_level_present_flag[MAX_SUB_LAYERS]; +} PTL; + +typedef struct HEVCVPS { + uint8_t vps_temporal_id_nesting_flag; + int vps_max_layers; + int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1 + + PTL ptl; + int vps_sub_layer_ordering_info_present_flag; + unsigned int vps_max_dec_pic_buffering[MAX_SUB_LAYERS]; + unsigned int vps_num_reorder_pics[MAX_SUB_LAYERS]; + unsigned int vps_max_latency_increase[MAX_SUB_LAYERS]; + int vps_max_layer_id; + int vps_num_layer_sets; ///< vps_num_layer_sets_minus1 + 1 + uint8_t vps_timing_info_present_flag; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint8_t vps_poc_proportional_to_timing_flag; + int vps_num_ticks_poc_diff_one; ///< vps_num_ticks_poc_diff_one_minus1 + 1 + int vps_num_hrd_parameters; +} HEVCVPS; + +typedef struct ScalingList { + /* This is a little wasteful, since sizeID 0 only needs 8 coeffs, + * and size ID 3 only has 2 arrays, not 6. */ + uint8_t sl[4][6][64]; + uint8_t sl_dc[2][6]; +} ScalingList; + +typedef struct HEVCSPS { + unsigned vps_id; + int chroma_format_idc; + uint8_t separate_colour_plane_flag; + + ///< output (i.e. cropped) values + int output_width, output_height; + HEVCWindow output_window; + + HEVCWindow pic_conf_win; + + int bit_depth; + int pixel_shift; + enum AVPixelFormat pix_fmt; + + unsigned int log2_max_poc_lsb; + int pcm_enabled_flag; + + int max_sub_layers; + struct { + int max_dec_pic_buffering; + int num_reorder_pics; + int max_latency_increase; + } temporal_layer[MAX_SUB_LAYERS]; + + VUI vui; + PTL ptl; + + uint8_t scaling_list_enable_flag; + ScalingList scaling_list; + + unsigned int nb_st_rps; + ShortTermRPS st_rps[MAX_SHORT_TERM_RPS_COUNT]; + + uint8_t amp_enabled_flag; + uint8_t sao_enabled; + + uint8_t long_term_ref_pics_present_flag; + uint16_t lt_ref_pic_poc_lsb_sps[32]; + uint8_t used_by_curr_pic_lt_sps_flag[32]; + uint8_t num_long_term_ref_pics_sps; + + struct { + uint8_t bit_depth; + uint8_t bit_depth_chroma; + unsigned int log2_min_pcm_cb_size; + unsigned int log2_max_pcm_cb_size; + uint8_t loop_filter_disable_flag; + } pcm; + uint8_t sps_temporal_mvp_enabled_flag; + uint8_t sps_strong_intra_smoothing_enable_flag; + + unsigned int log2_min_cb_size; + unsigned int log2_diff_max_min_coding_block_size; + unsigned int log2_min_tb_size; + unsigned int log2_max_trafo_size; + unsigned int log2_ctb_size; + unsigned int log2_min_pu_size; + + int max_transform_hierarchy_depth_inter; + int max_transform_hierarchy_depth_intra; + + int transform_skip_rotation_enabled_flag; + int transform_skip_context_enabled_flag; + int implicit_rdpcm_enabled_flag; + int explicit_rdpcm_enabled_flag; + int intra_smoothing_disabled_flag; + int persistent_rice_adaptation_enabled_flag; + + ///< coded frame dimension in various units + int width; + int height; + int ctb_width; + int ctb_height; + int ctb_size; + int min_cb_width; + int min_cb_height; + int min_tb_width; + int min_tb_height; + int min_pu_width; + int min_pu_height; + int tb_mask; + + int hshift[3]; + int vshift[3]; + + int qp_bd_offset; +} HEVCSPS; + +typedef struct HEVCPPS { + unsigned int sps_id; ///< seq_parameter_set_id + + uint8_t sign_data_hiding_flag; + + uint8_t cabac_init_present_flag; + + int num_ref_idx_l0_default_active; ///< num_ref_idx_l0_default_active_minus1 + 1 + int num_ref_idx_l1_default_active; ///< num_ref_idx_l1_default_active_minus1 + 1 + int pic_init_qp_minus26; + + uint8_t constrained_intra_pred_flag; + uint8_t transform_skip_enabled_flag; + + uint8_t cu_qp_delta_enabled_flag; + int diff_cu_qp_delta_depth; + + int cb_qp_offset; + int cr_qp_offset; + uint8_t pic_slice_level_chroma_qp_offsets_present_flag; + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_flag; + uint8_t output_flag_present_flag; + uint8_t transquant_bypass_enable_flag; + + uint8_t dependent_slice_segments_enabled_flag; + uint8_t tiles_enabled_flag; + uint8_t entropy_coding_sync_enabled_flag; + + int num_tile_columns; ///< num_tile_columns_minus1 + 1 + int num_tile_rows; ///< num_tile_rows_minus1 + 1 + uint8_t uniform_spacing_flag; + uint8_t loop_filter_across_tiles_enabled_flag; + + uint8_t seq_loop_filter_across_slices_enabled_flag; + + uint8_t deblocking_filter_control_present_flag; + uint8_t deblocking_filter_override_enabled_flag; + uint8_t disable_dbf; + int beta_offset; ///< beta_offset_div2 * 2 + int tc_offset; ///< tc_offset_div2 * 2 + + uint8_t scaling_list_data_present_flag; + ScalingList scaling_list; + + uint8_t lists_modification_present_flag; + int log2_parallel_merge_level; ///< log2_parallel_merge_level_minus2 + 2 + int num_extra_slice_header_bits; + uint8_t slice_header_extension_present_flag; + uint8_t log2_max_transform_skip_block_size; + uint8_t cross_component_prediction_enabled_flag; + uint8_t chroma_qp_offset_list_enabled_flag; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[5]; + int8_t cr_qp_offset_list[5]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + + // Inferred parameters + unsigned int *column_width; ///< ColumnWidth + unsigned int *row_height; ///< RowHeight + unsigned int *col_bd; ///< ColBd + unsigned int *row_bd; ///< RowBd + int *col_idxX; + + int *ctb_addr_rs_to_ts; ///< CtbAddrRSToTS + int *ctb_addr_ts_to_rs; ///< CtbAddrTSToRS + int *tile_id; ///< TileId + int *tile_pos_rs; ///< TilePosRS + int *min_tb_addr_zs; ///< MinTbAddrZS + int *min_tb_addr_zs_tab;///< MinTbAddrZS +} HEVCPPS; + +typedef struct SliceHeader { + unsigned int pps_id; + + ///< address (in raster order) of the first block in the current slice segment + unsigned int slice_segment_addr; + ///< address (in raster order) of the first block in the current slice + unsigned int slice_addr; + + enum SliceType slice_type; + + int pic_order_cnt_lsb; + + uint8_t first_slice_in_pic_flag; + uint8_t dependent_slice_segment_flag; + uint8_t pic_output_flag; + uint8_t colour_plane_id; + + ///< RPS coded in the slice header itself is stored here + ShortTermRPS slice_rps; + const ShortTermRPS *short_term_rps; + LongTermRPS long_term_rps; + unsigned int list_entry_lx[2][32]; + + uint8_t rpl_modification_flag[2]; + uint8_t no_output_of_prior_pics_flag; + uint8_t slice_temporal_mvp_enabled_flag; + + unsigned int nb_refs[2]; + + uint8_t slice_sample_adaptive_offset_flag[3]; + uint8_t mvd_l1_zero_flag; + + uint8_t cabac_init_flag; + uint8_t disable_deblocking_filter_flag; ///< slice_header_disable_deblocking_filter_flag + uint8_t slice_loop_filter_across_slices_enabled_flag; + uint8_t collocated_list; + + unsigned int collocated_ref_idx; + + int slice_qp_delta; + int slice_cb_qp_offset; + int slice_cr_qp_offset; + + uint8_t cu_chroma_qp_offset_enabled_flag; + + int beta_offset; ///< beta_offset_div2 * 2 + int tc_offset; ///< tc_offset_div2 * 2 + + unsigned int max_num_merge_cand; ///< 5 - 5_minus_max_num_merge_cand + + int *entry_point_offset; + int * offset; + int * size; + int num_entry_point_offsets; + + int8_t slice_qp; + + uint8_t luma_log2_weight_denom; + int16_t chroma_log2_weight_denom; + + int16_t luma_weight_l0[16]; + int16_t chroma_weight_l0[16][2]; + int16_t chroma_weight_l1[16][2]; + int16_t luma_weight_l1[16]; + + int16_t luma_offset_l0[16]; + int16_t chroma_offset_l0[16][2]; + + int16_t luma_offset_l1[16]; + int16_t chroma_offset_l1[16][2]; + + int slice_ctb_addr_rs; +} SliceHeader; + +typedef struct CodingUnit { + int x; + int y; + + enum PredMode pred_mode; ///< PredMode + enum PartMode part_mode; ///< PartMode + + uint8_t rqt_root_cbf; + + uint8_t pcm_flag; + + // Inferred parameters + uint8_t intra_split_flag; ///< IntraSplitFlag + uint8_t max_trafo_depth; ///< MaxTrafoDepth + uint8_t cu_transquant_bypass_flag; +} CodingUnit; + +typedef struct Mv { + int16_t x; ///< horizontal component of motion vector + int16_t y; ///< vertical component of motion vector +} Mv; + +typedef struct MvField { + DECLARE_ALIGNED(4, Mv, mv)[2]; + int8_t ref_idx[2]; + int8_t pred_flag; +} MvField; + +typedef struct NeighbourAvailable { + int cand_bottom_left; + int cand_left; + int cand_up; + int cand_up_left; + int cand_up_right; + int cand_up_right_sap; +} NeighbourAvailable; + +typedef struct PredictionUnit { + int mpm_idx; + int rem_intra_luma_pred_mode; + uint8_t intra_pred_mode[4]; + Mv mvd; + uint8_t merge_flag; + uint8_t intra_pred_mode_c[4]; + uint8_t chroma_mode_c[4]; +} PredictionUnit; + +typedef struct TransformUnit { + int cu_qp_delta; + + int res_scale_val; + + // Inferred parameters; + int intra_pred_mode; + int intra_pred_mode_c; + int chroma_mode_c; + uint8_t is_cu_qp_delta_coded; + uint8_t is_cu_chroma_qp_offset_coded; + int8_t cu_qp_offset_cb; + int8_t cu_qp_offset_cr; + uint8_t cross_pf; +} TransformUnit; + +typedef struct DBParams { + int beta_offset; + int tc_offset; +} DBParams; + +#define HEVC_FRAME_FLAG_OUTPUT (1 << 0) +#define HEVC_FRAME_FLAG_SHORT_REF (1 << 1) +#define HEVC_FRAME_FLAG_LONG_REF (1 << 2) +#define HEVC_FRAME_FLAG_BUMPING (1 << 3) + +typedef struct HEVCFrame { + AVFrame *frame; + ThreadFrame tf; +#ifdef USE_PRED + MvField *tab_mvf; + RefPicList *refPicList; + RefPicListTab **rpl_tab; +#endif + int ctb_count; + int poc; + struct HEVCFrame *collocated_ref; + + HEVCWindow window; + +#ifdef USE_PRED + AVBufferRef *tab_mvf_buf; + AVBufferRef *rpl_tab_buf; + AVBufferRef *rpl_buf; +#endif + + /** + * A sequence counter, so that old frames are output first + * after a POC reset + */ + uint16_t sequence; + + /** + * A combination of HEVC_FRAME_FLAG_* + */ + uint8_t flags; +} HEVCFrame; + +typedef struct HEVCNAL { + uint8_t *rbsp_buffer; + int rbsp_buffer_size; + + int size; + const uint8_t *data; +} HEVCNAL; + +typedef struct HEVCLocalContext { + uint8_t cabac_state[HEVC_CONTEXTS]; + + uint8_t stat_coeff[4]; + + uint8_t first_qp_group; + + GetBitContext gb; + CABACContext cc; + + int8_t qp_y; + int8_t curr_qp_y; + + int qPy_pred; + + TransformUnit tu; + + uint8_t ctb_left_flag; + uint8_t ctb_up_flag; + uint8_t ctb_up_right_flag; + uint8_t ctb_up_left_flag; + int end_of_tiles_x; + int end_of_tiles_y; + /* +7 is for subpixel interpolation, *2 for high bit depths */ + DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; + DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; + DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]); + + int ct_depth; + CodingUnit cu; + PredictionUnit pu; + NeighbourAvailable na; + +#define BOUNDARY_LEFT_SLICE (1 << 0) +#define BOUNDARY_LEFT_TILE (1 << 1) +#define BOUNDARY_UPPER_SLICE (1 << 2) +#define BOUNDARY_UPPER_TILE (1 << 3) + /* properties of the boundary of the current CTB for the purposes + * of the deblocking filter */ + int boundary_flags; +} HEVCLocalContext; + +typedef struct HEVCContext { + const AVClass *c; // needed by private avoptions + AVCodecContext *avctx; + + struct HEVCContext *sList[MAX_NB_THREADS]; + + HEVCLocalContext *HEVClcList[MAX_NB_THREADS]; + HEVCLocalContext *HEVClc; + + uint8_t threads_type; + uint8_t threads_number; + + int width; + int height; + + uint8_t *cabac_state; + + /** 1 if the independent slice segment header was successfully parsed */ + uint8_t slice_initialized; + + AVFrame *frame; + AVFrame *output_frame; +#ifdef USE_SAO_SMALL_BUFFER + uint8_t *sao_pixel_buffer; + uint8_t *sao_pixel_buffer_h[3]; + uint8_t *sao_pixel_buffer_v[3]; +#else + AVFrame *tmp_frame; + AVFrame *sao_frame; +#endif + const HEVCVPS *vps; + const HEVCSPS *sps; + const HEVCPPS *pps; + AVBufferRef *vps_list[MAX_VPS_COUNT]; + AVBufferRef *sps_list[MAX_SPS_COUNT]; + AVBufferRef *pps_list[MAX_PPS_COUNT]; + + AVBufferRef *current_sps; + +#ifdef USE_PRED + AVBufferPool *tab_mvf_pool; + AVBufferPool *rpl_tab_pool; + + ///< candidate references for the current frame + RefPicList rps[5]; +#endif + + SliceHeader sh; + SAOParams *sao; + DBParams *deblock; + enum NALUnitType nal_unit_type; + int temporal_id; ///< temporal_id_plus1 - 1 + HEVCFrame *ref; + HEVCFrame DPB[MAX_DPB_COUNT]; + int poc; + int pocTid0; + int slice_idx; ///< number of the slice being currently decoded + int eos; ///< current packet contains an EOS/EOB NAL + int last_eos; ///< last packet contains an EOS/EOB NAL + int max_ra; + int bs_width; + int bs_height; + + int is_decoded; + +#ifdef USE_FUNC_PTR + HEVCPredContext hpc; +#endif + HEVCDSPContext hevcdsp; +#ifdef USE_PRED + VideoDSPContext vdsp; +#endif +#if HAVE_BIGENDIAN + BswapDSPContext bdsp; +#endif + int8_t *qp_y_tab; + uint8_t *horizontal_bs; + uint8_t *vertical_bs; + + int32_t *tab_slice_address; + + // CU + uint8_t *skip_flag; + uint8_t *tab_ct_depth; + // PU + uint8_t *tab_ipm; + + uint8_t *cbf_luma; // cbf_luma of colocated TU + uint8_t *is_pcm; + + // CTB-level flags affecting loop filter operation + uint8_t *filter_slice_edges; + + /** used on BE to byteswap the lines for checksumming */ + uint8_t *checksum_buf; + int checksum_buf_size; + + /** + * Sequence counters for decoded and output frames, so that old + * frames are output first after a POC reset + */ + uint16_t seq_decode; + uint16_t seq_output; + + int enable_parallel_tiles; + int wpp_err; + int skipped_bytes; + int *skipped_bytes_pos; + int skipped_bytes_pos_size; + + int *skipped_bytes_nal; + int **skipped_bytes_pos_nal; + int *skipped_bytes_pos_size_nal; + + const uint8_t *data; + + HEVCNAL *nals; + int nb_nals; + int nals_allocated; + // type of the first VCL NAL of the current frame + enum NALUnitType first_nal_type; + +#ifdef USE_MD5 + // for checking the frame checksums + struct AVMD5 *md5_ctx; +#endif + uint8_t md5[3][16]; + uint8_t is_md5; + + uint8_t context_initialized; + uint8_t is_nalff; ///< this flag is != 0 if bitstream is encapsulated + ///< as a format defined in 14496-15 + int apply_defdispwin; + + int active_seq_parameter_set_id; + + int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) + int nuh_layer_id; + + /** frame packing arrangement variables */ + int sei_frame_packing_present; + int frame_packing_arrangement_type; + int content_interpretation_type; + int quincunx_subsampling; + + /** display orientation */ + int sei_display_orientation_present; + int sei_anticlockwise_rotation; + int sei_hflip, sei_vflip; + + int picture_struct; +} HEVCContext; + +int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps, + const HEVCSPS *sps, int is_slice_header); +int ff_hevc_decode_nal_vps(HEVCContext *s); +int ff_hevc_decode_nal_sps(HEVCContext *s); +int ff_hevc_decode_nal_pps(HEVCContext *s); +int ff_hevc_decode_nal_sei(HEVCContext *s); + +int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, + HEVCNAL *nal); + +/** + * Mark all frames in DPB as unused for reference. + */ +void ff_hevc_clear_refs(HEVCContext *s); + +/** + * Drop all frames currently in DPB. + */ +void ff_hevc_flush_dpb(HEVCContext *s); + +/** + * Compute POC of the current frame and return it. + */ +int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb); + +RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *frame, + int x0, int y0); + +/** + * Construct the reference picture sets for the current frame. + */ +int ff_hevc_frame_rps(HEVCContext *s); + +/** + * Construct the reference picture list(s) for the current slice. + */ +int ff_hevc_slice_rpl(HEVCContext *s); + +void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts); +void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts); +int ff_hevc_sao_merge_flag_decode(HEVCContext *s); +int ff_hevc_sao_type_idx_decode(HEVCContext *s); +int ff_hevc_sao_band_position_decode(HEVCContext *s); +int ff_hevc_sao_offset_abs_decode(HEVCContext *s); +int ff_hevc_sao_offset_sign_decode(HEVCContext *s); +int ff_hevc_sao_eo_class_decode(HEVCContext *s); +int ff_hevc_end_of_slice_flag_decode(HEVCContext *s); +int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s); +int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, + int x_cb, int y_cb); +int ff_hevc_pred_mode_decode(HEVCContext *s); +int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, + int x0, int y0); +int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size); +int ff_hevc_pcm_flag_decode(HEVCContext *s); +int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s); +int ff_hevc_mpm_idx_decode(HEVCContext *s); +int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s); +int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s); +int ff_hevc_merge_idx_decode(HEVCContext *s); +int ff_hevc_merge_flag_decode(HEVCContext *s); +int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH); +int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx); +int ff_hevc_mvp_lx_flag_decode(HEVCContext *s); +int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s); +int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size); +int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth); +int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth); +int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx); +int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx); + +/** + * Get the number of candidate references for the current frame. + */ +int ff_hevc_frame_nb_refs(HEVCContext *s); + +int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc); + +/** + * Find next frame in output order and put a reference to it in frame. + * @return 1 if a frame was output, 0 otherwise + */ +int ff_hevc_output_frame(HEVCContext *s, AVFrame *frame, int flush); + +void ff_hevc_bump_frame(HEVCContext *s); + +void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags); + +void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH); +void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH, int log2_cb_size, + int part_idx, int merge_idx, MvField *mv); +void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH, int log2_cb_size, + int part_idx, int merge_idx, + MvField *mv, int mvp_lx_flag, int LX); +void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase, + int log2_cb_size); +void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, + int log2_trafo_size); +int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s); +int ff_hevc_cu_qp_delta_abs(HEVCContext *s); +int ff_hevc_cu_chroma_qp_offset_flag(HEVCContext *s); +int ff_hevc_cu_chroma_qp_offset_idx(HEVCContext *s); +void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size); +void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size); +void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, + int log2_trafo_size, enum ScanType scan_idx, + int c_idx); + +void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size); + +#ifndef USE_FUNC_PTR +void intra_pred (HEVCContext *s, int x0, int y0, int log2_size, int c_idx); +#endif + +extern const uint8_t ff_hevc_qpel_extra_before[4]; +extern const uint8_t ff_hevc_qpel_extra_after[4]; +extern const uint8_t ff_hevc_qpel_extra[4]; + +extern const uint8_t ff_hevc_diag_scan4x4_x[16]; +extern const uint8_t ff_hevc_diag_scan4x4_y[16]; +extern const uint8_t ff_hevc_diag_scan8x8_x[64]; +extern const uint8_t ff_hevc_diag_scan8x8_y[64]; + +#endif /* AVCODEC_HEVC_H */ diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c new file mode 100644 index 0000000..5323ffc --- /dev/null +++ b/libavcodec/hevc_cabac.c @@ -0,0 +1,1601 @@ +/* + * HEVC CABAC decoding + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2012 - 2013 Gildas Cocherel + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#include "cabac_functions.h" +#include "hevc.h" + +#define CABAC_MAX_BIN 31 + +/** + * number of bin by SyntaxElement. + */ +av_unused static const int8_t num_bins_in_se[] = { + 1, // sao_merge_flag + 1, // sao_type_idx + 0, // sao_eo_class + 0, // sao_band_position + 0, // sao_offset_abs + 0, // sao_offset_sign + 0, // end_of_slice_flag + 3, // split_coding_unit_flag + 1, // cu_transquant_bypass_flag + 3, // skip_flag + 3, // cu_qp_delta + 1, // pred_mode + 4, // part_mode + 0, // pcm_flag + 1, // prev_intra_luma_pred_mode + 0, // mpm_idx + 0, // rem_intra_luma_pred_mode + 2, // intra_chroma_pred_mode + 1, // merge_flag + 1, // merge_idx + 5, // inter_pred_idc + 2, // ref_idx_l0 + 2, // ref_idx_l1 + 2, // abs_mvd_greater0_flag + 2, // abs_mvd_greater1_flag + 0, // abs_mvd_minus2 + 0, // mvd_sign_flag + 1, // mvp_lx_flag + 1, // no_residual_data_flag + 3, // split_transform_flag + 2, // cbf_luma + 4, // cbf_cb, cbf_cr + 2, // transform_skip_flag[][] + 2, // explicit_rdpcm_flag[][] + 2, // explicit_rdpcm_dir_flag[][] + 18, // last_significant_coeff_x_prefix + 18, // last_significant_coeff_y_prefix + 0, // last_significant_coeff_x_suffix + 0, // last_significant_coeff_y_suffix + 4, // significant_coeff_group_flag + 44, // significant_coeff_flag + 24, // coeff_abs_level_greater1_flag + 6, // coeff_abs_level_greater2_flag + 0, // coeff_abs_level_remaining + 0, // coeff_sign_flag + 8, // log2_res_scale_abs + 2, // res_scale_sign_flag + 1, // cu_chroma_qp_offset_flag + 1, // cu_chroma_qp_offset_idx +}; + +/** + * Offset to ctxIdx 0 in init_values and states, indexed by SyntaxElement. + */ +static const int elem_offset[sizeof(num_bins_in_se)] = { + 0, // sao_merge_flag + 1, // sao_type_idx + 2, // sao_eo_class + 2, // sao_band_position + 2, // sao_offset_abs + 2, // sao_offset_sign + 2, // end_of_slice_flag + 2, // split_coding_unit_flag + 5, // cu_transquant_bypass_flag + 6, // skip_flag + 9, // cu_qp_delta + 12, // pred_mode + 13, // part_mode + 17, // pcm_flag + 17, // prev_intra_luma_pred_mode + 18, // mpm_idx + 18, // rem_intra_luma_pred_mode + 18, // intra_chroma_pred_mode + 20, // merge_flag + 21, // merge_idx + 22, // inter_pred_idc + 27, // ref_idx_l0 + 29, // ref_idx_l1 + 31, // abs_mvd_greater0_flag + 33, // abs_mvd_greater1_flag + 35, // abs_mvd_minus2 + 35, // mvd_sign_flag + 35, // mvp_lx_flag + 36, // no_residual_data_flag + 37, // split_transform_flag + 40, // cbf_luma + 42, // cbf_cb, cbf_cr + 46, // transform_skip_flag[][] + 48, // explicit_rdpcm_flag[][] + 50, // explicit_rdpcm_dir_flag[][] + 52, // last_significant_coeff_x_prefix + 70, // last_significant_coeff_y_prefix + 88, // last_significant_coeff_x_suffix + 88, // last_significant_coeff_y_suffix + 88, // significant_coeff_group_flag + 92, // significant_coeff_flag + 136, // coeff_abs_level_greater1_flag + 160, // coeff_abs_level_greater2_flag + 166, // coeff_abs_level_remaining + 166, // coeff_sign_flag + 166, // log2_res_scale_abs + 174, // res_scale_sign_flag + 176, // cu_chroma_qp_offset_flag + 177, // cu_chroma_qp_offset_idx +}; + +#define CNU 154 +/** + * Indexed by init_type + */ +static const uint8_t init_values[3][HEVC_CONTEXTS] = { + { // sao_merge_flag + 153, + // sao_type_idx + 200, + // split_coding_unit_flag + 139, 141, 157, + // cu_transquant_bypass_flag + 154, + // skip_flag + CNU, CNU, CNU, + // cu_qp_delta + 154, 154, 154, + // pred_mode + CNU, + // part_mode + 184, CNU, CNU, CNU, + // prev_intra_luma_pred_mode + 184, + // intra_chroma_pred_mode + 63, 139, + // merge_flag + CNU, + // merge_idx + CNU, + // inter_pred_idc + CNU, CNU, CNU, CNU, CNU, + // ref_idx_l0 + CNU, CNU, + // ref_idx_l1 + CNU, CNU, + // abs_mvd_greater1_flag + CNU, CNU, + // abs_mvd_greater1_flag + CNU, CNU, + // mvp_lx_flag + CNU, + // no_residual_data_flag + CNU, + // split_transform_flag + 153, 138, 138, + // cbf_luma + 111, 141, + // cbf_cb, cbf_cr + 94, 138, 182, 154, + // transform_skip_flag + 139, 139, + // explicit_rdpcm_flag + 139, 139, + // explicit_rdpcm_dir_flag + 139, 139, + // last_significant_coeff_x_prefix + 110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111, + 79, 108, 123, 63, + // last_significant_coeff_y_prefix + 110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111, + 79, 108, 123, 63, + // significant_coeff_group_flag + 91, 171, 134, 141, + // significant_coeff_flag + 111, 111, 125, 110, 110, 94, 124, 108, 124, 107, 125, 141, 179, 153, + 125, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 140, + 139, 182, 182, 152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111, + 141, 111, + // coeff_abs_level_greater1_flag + 140, 92, 137, 138, 140, 152, 138, 139, 153, 74, 149, 92, 139, 107, + 122, 152, 140, 179, 166, 182, 140, 227, 122, 197, + // coeff_abs_level_greater2_flag + 138, 153, 136, 167, 152, 152, + // log2_res_scale_abs + 154, 154, 154, 154, 154, 154, 154, 154, + // res_scale_sign_flag + 154, 154, + // cu_chroma_qp_offset_flag + 154, + // cu_chroma_qp_offset_idx + 154, + }, + { // sao_merge_flag + 153, + // sao_type_idx + 185, + // split_coding_unit_flag + 107, 139, 126, + // cu_transquant_bypass_flag + 154, + // skip_flag + 197, 185, 201, + // cu_qp_delta + 154, 154, 154, + // pred_mode + 149, + // part_mode + 154, 139, 154, 154, + // prev_intra_luma_pred_mode + 154, + // intra_chroma_pred_mode + 152, 139, + // merge_flag + 110, + // merge_idx + 122, + // inter_pred_idc + 95, 79, 63, 31, 31, + // ref_idx_l0 + 153, 153, + // ref_idx_l1 + 153, 153, + // abs_mvd_greater1_flag + 140, 198, + // abs_mvd_greater1_flag + 140, 198, + // mvp_lx_flag + 168, + // no_residual_data_flag + 79, + // split_transform_flag + 124, 138, 94, + // cbf_luma + 153, 111, + // cbf_cb, cbf_cr + 149, 107, 167, 154, + // transform_skip_flag + 139, 139, + // explicit_rdpcm_flag + 139, 139, + // explicit_rdpcm_dir_flag + 139, 139, + // last_significant_coeff_x_prefix + 125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95, + 94, 108, 123, 108, + // last_significant_coeff_y_prefix + 125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95, + 94, 108, 123, 108, + // significant_coeff_group_flag + 121, 140, 61, 154, + // significant_coeff_flag + 155, 154, 139, 153, 139, 123, 123, 63, 153, 166, 183, 140, 136, 153, + 154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170, + 153, 123, 123, 107, 121, 107, 121, 167, 151, 183, 140, 151, 183, 140, + 140, 140, + // coeff_abs_level_greater1_flag + 154, 196, 196, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121, + 136, 137, 169, 194, 166, 167, 154, 167, 137, 182, + // coeff_abs_level_greater2_flag + 107, 167, 91, 122, 107, 167, + // log2_res_scale_abs + 154, 154, 154, 154, 154, 154, 154, 154, + // res_scale_sign_flag + 154, 154, + // cu_chroma_qp_offset_flag + 154, + // cu_chroma_qp_offset_idx + 154, + }, + { // sao_merge_flag + 153, + // sao_type_idx + 160, + // split_coding_unit_flag + 107, 139, 126, + // cu_transquant_bypass_flag + 154, + // skip_flag + 197, 185, 201, + // cu_qp_delta + 154, 154, 154, + // pred_mode + 134, + // part_mode + 154, 139, 154, 154, + // prev_intra_luma_pred_mode + 183, + // intra_chroma_pred_mode + 152, 139, + // merge_flag + 154, + // merge_idx + 137, + // inter_pred_idc + 95, 79, 63, 31, 31, + // ref_idx_l0 + 153, 153, + // ref_idx_l1 + 153, 153, + // abs_mvd_greater1_flag + 169, 198, + // abs_mvd_greater1_flag + 169, 198, + // mvp_lx_flag + 168, + // no_residual_data_flag + 79, + // split_transform_flag + 224, 167, 122, + // cbf_luma + 153, 111, + // cbf_cb, cbf_cr + 149, 92, 167, 154, + // transform_skip_flag + 139, 139, + // explicit_rdpcm_flag + 139, 139, + // explicit_rdpcm_dir_flag + 139, 139, + // last_significant_coeff_x_prefix + 125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111, + 79, 108, 123, 93, + // last_significant_coeff_y_prefix + 125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111, + 79, 108, 123, 93, + // significant_coeff_group_flag + 121, 140, 61, 154, + // significant_coeff_flag + 170, 154, 139, 153, 139, 123, 123, 63, 124, 166, 183, 140, 136, 153, + 154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170, + 153, 138, 138, 122, 121, 122, 121, 167, 151, 183, 140, 151, 183, 140, + 140, 140, + // coeff_abs_level_greater1_flag + 154, 196, 167, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121, + 136, 122, 169, 208, 166, 167, 154, 152, 167, 182, + // coeff_abs_level_greater2_flag + 107, 167, 91, 107, 107, 167, + // log2_res_scale_abs + 154, 154, 154, 154, 154, 154, 154, 154, + // res_scale_sign_flag + 154, 154, + // cu_chroma_qp_offset_flag + 154, + // cu_chroma_qp_offset_idx + 154, + }, +}; + +static const uint8_t scan_1x1[1] = { + 0, +}; + +static const uint8_t horiz_scan2x2_x[4] = { + 0, 1, 0, 1, +}; + +static const uint8_t horiz_scan2x2_y[4] = { + 0, 0, 1, 1 +}; + +static const uint8_t horiz_scan4x4_x[16] = { + 0, 1, 2, 3, + 0, 1, 2, 3, + 0, 1, 2, 3, + 0, 1, 2, 3, +}; + +static const uint8_t horiz_scan4x4_y[16] = { + 0, 0, 0, 0, + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, +}; + +static const uint8_t horiz_scan8x8_inv[8][8] = { + { 0, 1, 2, 3, 16, 17, 18, 19, }, + { 4, 5, 6, 7, 20, 21, 22, 23, }, + { 8, 9, 10, 11, 24, 25, 26, 27, }, + { 12, 13, 14, 15, 28, 29, 30, 31, }, + { 32, 33, 34, 35, 48, 49, 50, 51, }, + { 36, 37, 38, 39, 52, 53, 54, 55, }, + { 40, 41, 42, 43, 56, 57, 58, 59, }, + { 44, 45, 46, 47, 60, 61, 62, 63, }, +}; + +static const uint8_t diag_scan2x2_x[4] = { + 0, 0, 1, 1, +}; + +static const uint8_t diag_scan2x2_y[4] = { + 0, 1, 0, 1, +}; + +static const uint8_t diag_scan2x2_inv[2][2] = { + { 0, 2, }, + { 1, 3, }, +}; + +const uint8_t ff_hevc_diag_scan4x4_x[16] = { + 0, 0, 1, 0, + 1, 2, 0, 1, + 2, 3, 1, 2, + 3, 2, 3, 3, +}; + +const uint8_t ff_hevc_diag_scan4x4_y[16] = { + 0, 1, 0, 2, + 1, 0, 3, 2, + 1, 0, 3, 2, + 1, 3, 2, 3, +}; + +static const uint8_t diag_scan4x4_inv[4][4] = { + { 0, 2, 5, 9, }, + { 1, 4, 8, 12, }, + { 3, 7, 11, 14, }, + { 6, 10, 13, 15, }, +}; + +const uint8_t ff_hevc_diag_scan8x8_x[64] = { + 0, 0, 1, 0, + 1, 2, 0, 1, + 2, 3, 0, 1, + 2, 3, 4, 0, + 1, 2, 3, 4, + 5, 0, 1, 2, + 3, 4, 5, 6, + 0, 1, 2, 3, + 4, 5, 6, 7, + 1, 2, 3, 4, + 5, 6, 7, 2, + 3, 4, 5, 6, + 7, 3, 4, 5, + 6, 7, 4, 5, + 6, 7, 5, 6, + 7, 6, 7, 7, +}; + +const uint8_t ff_hevc_diag_scan8x8_y[64] = { + 0, 1, 0, 2, + 1, 0, 3, 2, + 1, 0, 4, 3, + 2, 1, 0, 5, + 4, 3, 2, 1, + 0, 6, 5, 4, + 3, 2, 1, 0, + 7, 6, 5, 4, + 3, 2, 1, 0, + 7, 6, 5, 4, + 3, 2, 1, 7, + 6, 5, 4, 3, + 2, 7, 6, 5, + 4, 3, 7, 6, + 5, 4, 7, 6, + 5, 7, 6, 7, +}; + +static const uint8_t diag_scan8x8_inv[8][8] = { + { 0, 2, 5, 9, 14, 20, 27, 35, }, + { 1, 4, 8, 13, 19, 26, 34, 42, }, + { 3, 7, 12, 18, 25, 33, 41, 48, }, + { 6, 11, 17, 24, 32, 40, 47, 53, }, + { 10, 16, 23, 31, 39, 46, 52, 57, }, + { 15, 22, 30, 38, 45, 51, 56, 60, }, + { 21, 29, 37, 44, 50, 55, 59, 62, }, + { 28, 36, 43, 49, 54, 58, 61, 63, }, +}; + +void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts) +{ + if (s->pps->entropy_coding_sync_enabled_flag && + (ctb_addr_ts % s->sps->ctb_width == 2 || + (s->sps->ctb_width == 2 && + ctb_addr_ts % s->sps->ctb_width == 0))) { + memcpy(s->cabac_state, s->HEVClc->cabac_state, HEVC_CONTEXTS); + } +} + +static void load_states(HEVCContext *s) +{ + memcpy(s->HEVClc->cabac_state, s->cabac_state, HEVC_CONTEXTS); +} + +static void cabac_reinit(HEVCLocalContext *lc) +{ + skip_bytes(&lc->cc, 0); +} + +static void cabac_init_decoder(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + skip_bits(gb, 1); + align_get_bits(gb); + ff_init_cabac_decoder(&s->HEVClc->cc, + gb->buffer + get_bits_count(gb) / 8, + (get_bits_left(gb) + 7) / 8); +} + +static void cabac_init_state(HEVCContext *s) +{ + int init_type = 2 - s->sh.slice_type; + int i; + + if (s->sh.cabac_init_flag && s->sh.slice_type != I_SLICE) + init_type ^= 3; + + for (i = 0; i < HEVC_CONTEXTS; i++) { + int init_value = init_values[init_type][i]; + int m = (init_value >> 4) * 5 - 45; + int n = ((init_value & 15) << 3) - 16; + int pre = 2 * (((m * av_clip(s->sh.slice_qp, 0, 51)) >> 4) + n) - 127; + + pre ^= pre >> 31; + if (pre > 124) + pre = 124 + (pre & 1); + s->HEVClc->cabac_state[i] = pre; + } + + for (i = 0; i < 4; i++) + s->HEVClc->stat_coeff[i] = 0; +} + +void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts) +{ + if (ctb_addr_ts == s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) { + cabac_init_decoder(s); + if (s->sh.dependent_slice_segment_flag == 0 || + (s->pps->tiles_enabled_flag && + s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1])) + cabac_init_state(s); + + if (!s->sh.first_slice_in_pic_flag && + s->pps->entropy_coding_sync_enabled_flag) { + if (ctb_addr_ts % s->sps->ctb_width == 0) { + if (s->sps->ctb_width == 1) + cabac_init_state(s); + else if (s->sh.dependent_slice_segment_flag == 1) + load_states(s); + } + } + } else { + if (s->pps->tiles_enabled_flag && + s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) { + if (s->threads_number == 1) + cabac_reinit(s->HEVClc); + else + cabac_init_decoder(s); + cabac_init_state(s); + } + if (s->pps->entropy_coding_sync_enabled_flag) { + if (ctb_addr_ts % s->sps->ctb_width == 0) { + get_cabac_terminate(&s->HEVClc->cc); + if (s->threads_number == 1) + cabac_reinit(s->HEVClc); + else + cabac_init_decoder(s); + + if (s->sps->ctb_width == 1) + cabac_init_state(s); + else + load_states(s); + } + } + } +} + +#define GET_CABAC(ctx) get_cabac(&s->HEVClc->cc, &s->HEVClc->cabac_state[ctx]) + +int ff_hevc_sao_merge_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[SAO_MERGE_FLAG]); +} + +int ff_hevc_sao_type_idx_decode(HEVCContext *s) +{ + if (!GET_CABAC(elem_offset[SAO_TYPE_IDX])) + return 0; + + if (!get_cabac_bypass(&s->HEVClc->cc)) + return SAO_BAND; + return SAO_EDGE; +} + +int ff_hevc_sao_band_position_decode(HEVCContext *s) +{ + int i; + int value = get_cabac_bypass(&s->HEVClc->cc); + + for (i = 0; i < 4; i++) + value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc); + return value; +} + +int ff_hevc_sao_offset_abs_decode(HEVCContext *s) +{ + int i = 0; + int length = (1 << (FFMIN(s->sps->bit_depth, 10) - 5)) - 1; + + while (i < length && get_cabac_bypass(&s->HEVClc->cc)) + i++; + return i; +} + +int ff_hevc_sao_offset_sign_decode(HEVCContext *s) +{ + return get_cabac_bypass(&s->HEVClc->cc); +} + +int ff_hevc_sao_eo_class_decode(HEVCContext *s) +{ + int ret = get_cabac_bypass(&s->HEVClc->cc) << 1; + ret |= get_cabac_bypass(&s->HEVClc->cc); + return ret; +} + +int ff_hevc_end_of_slice_flag_decode(HEVCContext *s) +{ + return get_cabac_terminate(&s->HEVClc->cc); +} + +int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[CU_TRANSQUANT_BYPASS_FLAG]); +} + +int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb) +{ + int min_cb_width = s->sps->min_cb_width; + int inc = 0; + int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1); + int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1); + + if (s->HEVClc->ctb_left_flag || x0b) + inc = !!SAMPLE_CTB(s->skip_flag, x_cb - 1, y_cb); + if (s->HEVClc->ctb_up_flag || y0b) + inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb - 1); + + return GET_CABAC(elem_offset[SKIP_FLAG] + inc); +} + +int ff_hevc_cu_qp_delta_abs(HEVCContext *s) +{ + int prefix_val = 0; + int suffix_val = 0; + int inc = 0; + + while (prefix_val < 5 && GET_CABAC(elem_offset[CU_QP_DELTA] + inc)) { + prefix_val++; + inc = 1; + } + if (prefix_val >= 5) { + int k = 0; + while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) { + suffix_val += 1 << k; + k++; + } + if (k == CABAC_MAX_BIN) + av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k); + + while (k--) + suffix_val += get_cabac_bypass(&s->HEVClc->cc) << k; + } + return prefix_val + suffix_val; +} + +int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s) +{ + return get_cabac_bypass(&s->HEVClc->cc); +} + +int ff_hevc_cu_chroma_qp_offset_flag(HEVCContext *s) +{ + return GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_FLAG]); +} + +int ff_hevc_cu_chroma_qp_offset_idx(HEVCContext *s) +{ + int c_max= FFMAX(5, s->pps->chroma_qp_offset_list_len_minus1); + int i = 0; + + while (i < c_max && GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_IDX])) + i++; + + return i; +} + +int ff_hevc_pred_mode_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[PRED_MODE_FLAG]); +} + +int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0) +{ + int inc = 0, depth_left = 0, depth_top = 0; + int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1); + int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1); + int x_cb = x0 >> s->sps->log2_min_cb_size; + int y_cb = y0 >> s->sps->log2_min_cb_size; + + if (s->HEVClc->ctb_left_flag || x0b) + depth_left = s->tab_ct_depth[(y_cb) * s->sps->min_cb_width + x_cb - 1]; + if (s->HEVClc->ctb_up_flag || y0b) + depth_top = s->tab_ct_depth[(y_cb - 1) * s->sps->min_cb_width + x_cb]; + + inc += (depth_left > ct_depth); + inc += (depth_top > ct_depth); + + return GET_CABAC(elem_offset[SPLIT_CODING_UNIT_FLAG] + inc); +} + + +#ifdef USE_PRED +int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size) +{ + if (GET_CABAC(elem_offset[PART_MODE])) // 1 + return PART_2Nx2N; + if (log2_cb_size == s->sps->log2_min_cb_size) { + if (s->HEVClc->cu.pred_mode == MODE_INTRA) // 0 + return PART_NxN; + if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01 + return PART_2NxN; + if (log2_cb_size == 3) // 00 + return PART_Nx2N; + if (GET_CABAC(elem_offset[PART_MODE] + 2)) // 001 + return PART_Nx2N; + return PART_NxN; // 000 + } + + if (!s->sps->amp_enabled_flag) { + if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01 + return PART_2NxN; + return PART_Nx2N; + } + + if (GET_CABAC(elem_offset[PART_MODE] + 1)) { // 01X, 01XX + if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 011 + return PART_2NxN; + if (get_cabac_bypass(&s->HEVClc->cc)) // 0101 + return PART_2NxnD; + return PART_2NxnU; // 0100 + } + + if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 001 + return PART_Nx2N; + if (get_cabac_bypass(&s->HEVClc->cc)) // 0001 + return PART_nRx2N; + return PART_nLx2N; // 0000 +} +#else +int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size) +{ + if (GET_CABAC(elem_offset[PART_MODE])) // 1 + return PART_2Nx2N; + else + return PART_NxN; +} +#endif + +int ff_hevc_pcm_flag_decode(HEVCContext *s) +{ + return get_cabac_terminate(&s->HEVClc->cc); +} + +int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[PREV_INTRA_LUMA_PRED_FLAG]); +} + +int ff_hevc_mpm_idx_decode(HEVCContext *s) +{ + int i = 0; + while (i < 2 && get_cabac_bypass(&s->HEVClc->cc)) + i++; + return i; +} + +int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s) +{ + int i; + int value = get_cabac_bypass(&s->HEVClc->cc); + + for (i = 0; i < 4; i++) + value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc); + return value; +} + +int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s) +{ + int ret; + if (!GET_CABAC(elem_offset[INTRA_CHROMA_PRED_MODE])) + return 4; + + ret = get_cabac_bypass(&s->HEVClc->cc) << 1; + ret |= get_cabac_bypass(&s->HEVClc->cc); + return ret; +} + +int ff_hevc_merge_idx_decode(HEVCContext *s) +{ + int i = GET_CABAC(elem_offset[MERGE_IDX]); + + if (i != 0) { + while (i < s->sh.max_num_merge_cand-1 && get_cabac_bypass(&s->HEVClc->cc)) + i++; + } + return i; +} + +int ff_hevc_merge_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[MERGE_FLAG]); +} + +int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH) +{ + if (nPbW + nPbH == 12) + return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4); + if (GET_CABAC(elem_offset[INTER_PRED_IDC] + s->HEVClc->ct_depth)) + return PRED_BI; + + return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4); +} + +int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx) +{ + int i = 0; + int max = num_ref_idx_lx - 1; + int max_ctx = FFMIN(max, 2); + + while (i < max_ctx && GET_CABAC(elem_offset[REF_IDX_L0] + i)) + i++; + if (i == 2) { + while (i < max && get_cabac_bypass(&s->HEVClc->cc)) + i++; + } + + return i; +} + +int ff_hevc_mvp_lx_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[MVP_LX_FLAG]); +} + +int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[NO_RESIDUAL_DATA_FLAG]); +} + +static av_always_inline int abs_mvd_greater0_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[ABS_MVD_GREATER0_FLAG]); +} + +static av_always_inline int abs_mvd_greater1_flag_decode(HEVCContext *s) +{ + return GET_CABAC(elem_offset[ABS_MVD_GREATER1_FLAG] + 1); +} + +static av_always_inline int mvd_decode(HEVCContext *s) +{ + int ret = 2; + int k = 1; + + while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) { + ret += 1 << k; + k++; + } + if (k == CABAC_MAX_BIN) + av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k); + while (k--) + ret += get_cabac_bypass(&s->HEVClc->cc) << k; + return get_cabac_bypass_sign(&s->HEVClc->cc, -ret); +} + +static av_always_inline int mvd_sign_flag_decode(HEVCContext *s) +{ + return get_cabac_bypass_sign(&s->HEVClc->cc, -1); +} + +int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size) +{ + return GET_CABAC(elem_offset[SPLIT_TRANSFORM_FLAG] + 5 - log2_trafo_size); +} + +int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth) +{ + return GET_CABAC(elem_offset[CBF_CB_CR] + trafo_depth); +} + +int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth) +{ + return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth); +} + +static int ff_hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx) +{ + return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx); +} + +static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx) +{ + return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + !!c_idx); +} + +static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx) +{ + return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + !!c_idx); +} + +int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx) { + int i =0; + + while (i < 4 && GET_CABAC(elem_offset[LOG2_RES_SCALE_ABS] + 4 * idx + i)) + i++; + + return i; +} + +int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx) { + return GET_CABAC(elem_offset[RES_SCALE_SIGN_FLAG] + idx); +} + +static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx, + int log2_size, int *last_scx_prefix, int *last_scy_prefix) +{ + int i = 0; + int max = (log2_size << 1) - 1; + int ctx_offset, ctx_shift; + + if (!c_idx) { + ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2); + ctx_shift = (log2_size + 1) >> 2; + } else { + ctx_offset = 15; + ctx_shift = log2_size - 2; + } + while (i < max && + GET_CABAC(elem_offset[LAST_SIGNIFICANT_COEFF_X_PREFIX] + (i >> ctx_shift) + ctx_offset)) + i++; + *last_scx_prefix = i; + + i = 0; + while (i < max && + GET_CABAC(elem_offset[LAST_SIGNIFICANT_COEFF_Y_PREFIX] + (i >> ctx_shift) + ctx_offset)) + i++; + *last_scy_prefix = i; +} + +static av_always_inline int last_significant_coeff_suffix_decode(HEVCContext *s, + int last_significant_coeff_prefix) +{ + int i; + int length = (last_significant_coeff_prefix >> 1) - 1; + int value = get_cabac_bypass(&s->HEVClc->cc); + + for (i = 1; i < length; i++) + value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc); + return value; +} + +static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg) +{ + int inc; + + inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0); + + return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc); +} +static av_always_inline int significant_coeff_flag_decode(HEVCContext *s, int x_c, int y_c, + int offset, const uint8_t *ctx_idx_map) +{ + int inc = ctx_idx_map[(y_c << 2) + x_c] + offset; + return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc); +} + +static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int c_idx, int offset) +{ + return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + offset); +} + +static av_always_inline int coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int inc) +{ + + if (c_idx > 0) + inc += 16; + + return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + inc); +} + +static av_always_inline int coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx, int inc) +{ + if (c_idx > 0) + inc += 4; + + return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc); +} + +static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int rc_rice_param) +{ + int prefix = 0; + int suffix = 0; + int last_coeff_abs_level_remaining; + int i; + + while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) + prefix++; + if (prefix == CABAC_MAX_BIN) + av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix); + if (prefix < 3) { + for (i = 0; i < rc_rice_param; i++) + suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); + last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix; + } else { + int prefix_minus3 = prefix - 3; + for (i = 0; i < prefix_minus3 + rc_rice_param; i++) + suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); + last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1) + << rc_rice_param) + suffix; + } + return last_coeff_abs_level_remaining; +} + +static av_always_inline int coeff_sign_flag_decode(HEVCContext *s, uint8_t nb) +{ + int i; + int ret = 0; + + for (i = 0; i < nb; i++) + ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc); + return ret; +} + +void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, + int log2_trafo_size, enum ScanType scan_idx, + int c_idx) +{ +#define GET_COORD(offset, n) \ + do { \ + x_c = (x_cg << 2) + scan_x_off[n]; \ + y_c = (y_cg << 2) + scan_y_off[n]; \ + } while (0) + HEVCLocalContext *lc = s->HEVClc; + int transform_skip_flag = 0; + + int last_significant_coeff_x, last_significant_coeff_y; + int last_scan_pos; + int n_end; + int num_coeff = 0; + int greater1_ctx = 1; + + int num_last_subset; + int x_cg_last_sig, y_cg_last_sig; + + const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off; + + ptrdiff_t stride = s->frame->linesize[c_idx]; + int hshift = s->sps->hshift[c_idx]; + int vshift = s->sps->vshift[c_idx]; + uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride + + ((x0 >> hshift) << s->sps->pixel_shift)]; + int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer); + uint8_t significant_coeff_group_flag[8][8] = {{0}}; + int explicit_rdpcm_flag = 0; + int explicit_rdpcm_dir_flag; + + int trafo_size = 1 << log2_trafo_size; + int i; + int qp,shift,add,scale,scale_m; + const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 }; + const uint8_t *scale_matrix = NULL; + uint8_t dc_scale; + int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode : + lc->tu.intra_pred_mode_c; + + memset(coeffs, 0, trafo_size * trafo_size * sizeof(int16_t)); + + // Derive QP for dequant + if (!lc->cu.cu_transquant_bypass_flag) { + static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 }; + static const uint8_t rem6[51 + 4 * 6 + 1] = { + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, + 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, + 4, 5, 0, 1, 2, 3, 4, 5, 0, 1 + }; + + static const uint8_t div6[51 + 4 * 6 + 1] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, 11, 12, 12 + }; + int qp_y = lc->qp_y; + + if (s->pps->transform_skip_enabled_flag && + log2_trafo_size <= s->pps->log2_max_transform_skip_block_size) { + transform_skip_flag = ff_hevc_transform_skip_flag_decode(s, c_idx); + } + + if (c_idx == 0) { + qp = qp_y + s->sps->qp_bd_offset; + } else { + int qp_i, offset; + + if (c_idx == 1) + offset = s->pps->cb_qp_offset + s->sh.slice_cb_qp_offset + + lc->tu.cu_qp_offset_cb; + else + offset = s->pps->cr_qp_offset + s->sh.slice_cr_qp_offset + + lc->tu.cu_qp_offset_cr; + + qp_i = av_clip(qp_y + offset, - s->sps->qp_bd_offset, 57); + if (s->sps->chroma_format_idc == 1) { + if (qp_i < 30) + qp = qp_i; + else if (qp_i > 43) + qp = qp_i - 6; + else + qp = qp_c[qp_i - 30]; + } else { + if (qp_i > 51) + qp = 51; + else + qp = qp_i; + } + + qp += s->sps->qp_bd_offset; + } + + shift = s->sps->bit_depth + log2_trafo_size - 5; + add = 1 << (shift-1); + scale = level_scale[rem6[qp]] << (div6[qp]); + scale_m = 16; // default when no custom scaling lists. + dc_scale = 16; + + if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { + const ScalingList *sl = s->pps->scaling_list_data_present_flag ? + &s->pps->scaling_list : &s->sps->scaling_list; + int matrix_id = lc->cu.pred_mode != MODE_INTRA; + + matrix_id = 3 * matrix_id + c_idx; + + scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id]; + if (log2_trafo_size >= 4) + dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id]; + } + } else { + shift = 0; + add = 0; + scale = 0; + dc_scale = 0; + } + +#ifdef USE_PRED + if (lc->cu.pred_mode == MODE_INTER && s->sps->explicit_rdpcm_enabled_flag && + (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { + explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx); + if (explicit_rdpcm_flag) { + explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx); + } + } +#endif + + last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size, + &last_significant_coeff_x, &last_significant_coeff_y); + + if (last_significant_coeff_x > 3) { + int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_x); + last_significant_coeff_x = (1 << ((last_significant_coeff_x >> 1) - 1)) * + (2 + (last_significant_coeff_x & 1)) + + suffix; + } + + if (last_significant_coeff_y > 3) { + int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_y); + last_significant_coeff_y = (1 << ((last_significant_coeff_y >> 1) - 1)) * + (2 + (last_significant_coeff_y & 1)) + + suffix; + } + + if (scan_idx == SCAN_VERT) + FFSWAP(int, last_significant_coeff_x, last_significant_coeff_y); + + x_cg_last_sig = last_significant_coeff_x >> 2; + y_cg_last_sig = last_significant_coeff_y >> 2; + + switch (scan_idx) { + case SCAN_DIAG: { + int last_x_c = last_significant_coeff_x & 3; + int last_y_c = last_significant_coeff_y & 3; + + scan_x_off = ff_hevc_diag_scan4x4_x; + scan_y_off = ff_hevc_diag_scan4x4_y; + num_coeff = diag_scan4x4_inv[last_y_c][last_x_c]; + if (trafo_size == 4) { + scan_x_cg = scan_1x1; + scan_y_cg = scan_1x1; + } else if (trafo_size == 8) { + num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4; + scan_x_cg = diag_scan2x2_x; + scan_y_cg = diag_scan2x2_y; + } else if (trafo_size == 16) { + num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4; + scan_x_cg = ff_hevc_diag_scan4x4_x; + scan_y_cg = ff_hevc_diag_scan4x4_y; + } else { // trafo_size == 32 + num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4; + scan_x_cg = ff_hevc_diag_scan8x8_x; + scan_y_cg = ff_hevc_diag_scan8x8_y; + } + break; + } + case SCAN_HORIZ: + scan_x_cg = horiz_scan2x2_x; + scan_y_cg = horiz_scan2x2_y; + scan_x_off = horiz_scan4x4_x; + scan_y_off = horiz_scan4x4_y; + num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x]; + break; + default: //SCAN_VERT + scan_x_cg = horiz_scan2x2_y; + scan_y_cg = horiz_scan2x2_x; + scan_x_off = horiz_scan4x4_y; + scan_y_off = horiz_scan4x4_x; + num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y]; + break; + } + num_coeff++; + num_last_subset = (num_coeff - 1) >> 4; + + for (i = num_last_subset; i >= 0; i--) { + int n, m; + int x_cg, y_cg, x_c, y_c, pos; + int implicit_non_zero_coeff = 0; + int64_t trans_coeff_level; + int prev_sig = 0; + int offset = i << 4; + int rice_init = 0; + + uint8_t significant_coeff_flag_idx[16]; + uint8_t nb_significant_coeff_flag = 0; + + x_cg = scan_x_cg[i]; + y_cg = scan_y_cg[i]; + + if ((i < num_last_subset) && (i > 0)) { + int ctx_cg = 0; + if (x_cg < (1 << (log2_trafo_size - 2)) - 1) + ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg]; + if (y_cg < (1 << (log2_trafo_size - 2)) - 1) + ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1]; + + significant_coeff_group_flag[x_cg][y_cg] = + significant_coeff_group_flag_decode(s, c_idx, ctx_cg); + implicit_non_zero_coeff = 1; + } else { + significant_coeff_group_flag[x_cg][y_cg] = + ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) || + (x_cg == 0 && y_cg == 0)); + } + + last_scan_pos = num_coeff - offset - 1; + + if (i == num_last_subset) { + n_end = last_scan_pos - 1; + significant_coeff_flag_idx[0] = last_scan_pos; + nb_significant_coeff_flag = 1; + } else { + n_end = 15; + } + + if (x_cg < ((1 << log2_trafo_size) - 1) >> 2) + prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg]; + if (y_cg < ((1 << log2_trafo_size) - 1) >> 2) + prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1); + + if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) { + static const uint8_t ctx_idx_map[] = { + 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2 + 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0 + 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1 + 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // default + }; + const uint8_t *ctx_idx_map_p; + int scf_offset = 0; + if (s->sps->transform_skip_context_enabled_flag && + (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { + ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16]; + if (c_idx == 0) { + scf_offset = 40; + } else { + scf_offset = 14 + 27; + } + } else { + if (c_idx != 0) + scf_offset = 27; + if (log2_trafo_size == 2) { + ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0]; + } else { + ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4]; + if (c_idx == 0) { + if ((x_cg > 0 || y_cg > 0)) + scf_offset += 3; + if (log2_trafo_size == 3) { + scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15; + } else { + scf_offset += 21; + } + } else { + if (log2_trafo_size == 3) + scf_offset += 9; + else + scf_offset += 12; + } + } + } + for (n = n_end; n > 0; n--) { + x_c = scan_x_off[n]; + y_c = scan_y_off[n]; + if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) { + significant_coeff_flag_idx[nb_significant_coeff_flag] = n; + nb_significant_coeff_flag++; + implicit_non_zero_coeff = 0; + } + } + if (implicit_non_zero_coeff == 0) { + if (s->sps->transform_skip_context_enabled_flag && + (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { + if (c_idx == 0) { + scf_offset = 42; + } else { + scf_offset = 16 + 27; + } + } else { + if (i == 0) { + if (c_idx == 0) + scf_offset = 0; + else + scf_offset = 27; + } else { + scf_offset = 2 + scf_offset; + } + } + if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) { + significant_coeff_flag_idx[nb_significant_coeff_flag] = 0; + nb_significant_coeff_flag++; + } + } else { + significant_coeff_flag_idx[nb_significant_coeff_flag] = 0; + nb_significant_coeff_flag++; + } + } + + n_end = nb_significant_coeff_flag; + + + if (n_end) { + int first_nz_pos_in_cg; + int last_nz_pos_in_cg; + int c_rice_param = 0; + int first_greater1_coeff_idx = -1; + uint8_t coeff_abs_level_greater1_flag[8]; + uint16_t coeff_sign_flag; + int sum_abs = 0; + int sign_hidden; + int sb_type; + + + // initialize first elem of coeff_bas_level_greater1_flag + int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0; + + if (s->sps->persistent_rice_adaptation_enabled_flag) { + if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag) + sb_type = 2 * (c_idx == 0 ? 1 : 0); + else + sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1; + c_rice_param = lc->stat_coeff[sb_type] / 4; + } + + if (!(i == num_last_subset) && greater1_ctx == 0) + ctx_set++; + greater1_ctx = 1; + last_nz_pos_in_cg = significant_coeff_flag_idx[0]; + + for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) { + int inc = (ctx_set << 2) + greater1_ctx; + coeff_abs_level_greater1_flag[m] = + coeff_abs_level_greater1_flag_decode(s, c_idx, inc); + if (coeff_abs_level_greater1_flag[m]) { + greater1_ctx = 0; + if (first_greater1_coeff_idx == -1) + first_greater1_coeff_idx = m; + } else if (greater1_ctx > 0 && greater1_ctx < 3) { + greater1_ctx++; + } + } + first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1]; + + if (lc->cu.cu_transquant_bypass_flag || + (lc->cu.pred_mode == MODE_INTRA && + s->sps->implicit_rdpcm_enabled_flag && transform_skip_flag && + (pred_mode_intra == 10 || pred_mode_intra == 26 )) || + explicit_rdpcm_flag) + sign_hidden = 0; + else + sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4); + + if (first_greater1_coeff_idx != -1) { + coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set); + } + if (!s->pps->sign_data_hiding_flag || !sign_hidden ) { + coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag); + } else { + coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1)); + } + + for (m = 0; m < n_end; m++) { + n = significant_coeff_flag_idx[m]; + GET_COORD(offset, n); + if (m < 8) { + trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m]; + if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) { + int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param); + + trans_coeff_level += last_coeff_abs_level_remaining; + if (trans_coeff_level > (3 << c_rice_param)) + c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); + if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) { + int c_rice_p_init = lc->stat_coeff[sb_type] / 4; + if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) + lc->stat_coeff[sb_type]++; + else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init)) + if (lc->stat_coeff[sb_type] > 0) + lc->stat_coeff[sb_type]--; + rice_init = 1; + } + } + } else { + int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param); + + trans_coeff_level = 1 + last_coeff_abs_level_remaining; + if (trans_coeff_level > (3 << c_rice_param)) + c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); + if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) { + int c_rice_p_init = lc->stat_coeff[sb_type] / 4; + if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) + lc->stat_coeff[sb_type]++; + else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init)) + if (lc->stat_coeff[sb_type] > 0) + lc->stat_coeff[sb_type]--; + rice_init = 1; + } + } + if (s->pps->sign_data_hiding_flag && sign_hidden) { + sum_abs += trans_coeff_level; + if (n == first_nz_pos_in_cg && (sum_abs&1)) + trans_coeff_level = -trans_coeff_level; + } + if (coeff_sign_flag >> 15) + trans_coeff_level = -trans_coeff_level; + coeff_sign_flag <<= 1; + if(!lc->cu.cu_transquant_bypass_flag) { + if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { + if(y_c || x_c || log2_trafo_size < 4) { + switch(log2_trafo_size) { + case 3: pos = (y_c << 3) + x_c; break; + case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break; + case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break; + default: pos = (y_c << 2) + x_c; break; + } + scale_m = scale_matrix[pos]; + } else { + scale_m = dc_scale; + } + } + trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift; + if(trans_coeff_level < 0) { + if((~trans_coeff_level) & 0xFffffffffff8000) + trans_coeff_level = -32768; + } else { + if(trans_coeff_level & 0xffffffffffff8000) + trans_coeff_level = 32767; + } + } + coeffs[y_c * trafo_size + x_c] = trans_coeff_level; + } + } + } + + if (lc->cu.cu_transquant_bypass_flag) { + if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag && + (pred_mode_intra == 10 || pred_mode_intra == 26))) { + int mode = s->sps->implicit_rdpcm_enabled_flag ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag; + + s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode); + } + } else { + if (transform_skip_flag) { + int rot = s->sps->transform_skip_rotation_enabled_flag && + log2_trafo_size == 2 && + lc->cu.pred_mode == MODE_INTRA; + if (rot) { + for (i = 0; i < 8; i++) + FFSWAP(int16_t, coeffs[i], coeffs[16 - i - 1]); + } + + s->hevcdsp.transform_skip(coeffs, log2_trafo_size BIT_DEPTH_ARG2(s->sps->bit_depth)); + + if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag && + lc->cu.pred_mode == MODE_INTRA && + (pred_mode_intra == 10 || pred_mode_intra == 26))) { + int mode = explicit_rdpcm_flag ? explicit_rdpcm_dir_flag : (pred_mode_intra == 26); + + s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode); + } + } else if (lc->cu.pred_mode == MODE_INTRA && c_idx == 0 && log2_trafo_size == 2) { + s->hevcdsp.idct_4x4_luma(coeffs BIT_DEPTH_ARG2(s->sps->bit_depth)); + } else { + int max_xy = FFMAX(last_significant_coeff_x, last_significant_coeff_y); + if (max_xy == 0) + s->hevcdsp.idct_dc[log2_trafo_size-2](coeffs BIT_DEPTH_ARG2(s->sps->bit_depth)); + else { + int col_limit = last_significant_coeff_x + last_significant_coeff_y + 4; + if (max_xy < 4) + col_limit = FFMIN(4, col_limit); + else if (max_xy < 8) + col_limit = FFMIN(8, col_limit); + else if (max_xy < 12) + col_limit = FFMIN(24, col_limit); + s->hevcdsp.idct[log2_trafo_size-2](coeffs, col_limit BIT_DEPTH_ARG2(s->sps->bit_depth)); + } + } + } + if (lc->tu.cross_pf) { + int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer; + + for (i = 0; i < (trafo_size * trafo_size); i++) { + coeffs[i] = coeffs[i] + ((lc->tu.res_scale_val * coeffs_y[i]) >> 3); + } + } + s->hevcdsp.transform_add[log2_trafo_size-2](dst, coeffs, stride BIT_DEPTH_ARG2(s->sps->bit_depth)); +} + +#ifdef USE_PRED +void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size) +{ + HEVCLocalContext *lc = s->HEVClc; + int x = abs_mvd_greater0_flag_decode(s); + int y = abs_mvd_greater0_flag_decode(s); + + if (x) + x += abs_mvd_greater1_flag_decode(s); + if (y) + y += abs_mvd_greater1_flag_decode(s); + + switch (x) { + case 2: lc->pu.mvd.x = mvd_decode(s); break; + case 1: lc->pu.mvd.x = mvd_sign_flag_decode(s); break; + case 0: lc->pu.mvd.x = 0; break; + } + + switch (y) { + case 2: lc->pu.mvd.y = mvd_decode(s); break; + case 1: lc->pu.mvd.y = mvd_sign_flag_decode(s); break; + case 0: lc->pu.mvd.y = 0; break; + } +} +#endif diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c new file mode 100644 index 0000000..2b2a567 --- /dev/null +++ b/libavcodec/hevc_filter.c @@ -0,0 +1,917 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 Seppo Tomperi + * Copyright (C) 2013 Wassim Hamidouche + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/internal.h" + +#include "cabac_functions.h" +#include "golomb.h" +#include "hevc.h" + +#include "bit_depth_template.c" + +#define LUMA 0 +#define CB 1 +#define CR 2 + +static const uint8_t tctable[54] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // QP 0...18 + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, // QP 19...37 + 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 24 // QP 38...53 +}; + +static const uint8_t betatable[52] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, // QP 0...18 + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, // QP 19...37 + 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 // QP 38...51 +}; + +static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset) +{ + static const uint8_t qp_c[] = { + 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 + }; + int qp, qp_i, offset, idxt; + + // slice qp offset is not used for deblocking + if (c_idx == 1) + offset = s->pps->cb_qp_offset; + else + offset = s->pps->cr_qp_offset; + + qp_i = av_clip(qp_y + offset, 0, 57); + if (s->sps->chroma_format_idc == 1) { + if (qp_i < 30) + qp = qp_i; + else if (qp_i > 43) + qp = qp_i - 6; + else + qp = qp_c[qp_i - 30]; + } else { + qp = av_clip(qp_i, 0, 51); + } + + idxt = av_clip(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53); + return tctable[idxt]; +} + +static int get_qPy_pred(HEVCContext *s, int xBase, int yBase, int log2_cb_size) +{ + HEVCLocalContext *lc = s->HEVClc; + int ctb_size_mask = (1 << s->sps->log2_ctb_size) - 1; + int MinCuQpDeltaSizeMask = (1 << (s->sps->log2_ctb_size - + s->pps->diff_cu_qp_delta_depth)) - 1; + int xQgBase = xBase - (xBase & MinCuQpDeltaSizeMask); + int yQgBase = yBase - (yBase & MinCuQpDeltaSizeMask); + int min_cb_width = s->sps->min_cb_width; + int x_cb = xQgBase >> s->sps->log2_min_cb_size; + int y_cb = yQgBase >> s->sps->log2_min_cb_size; + int availableA = (xBase & ctb_size_mask) && + (xQgBase & ctb_size_mask); + int availableB = (yBase & ctb_size_mask) && + (yQgBase & ctb_size_mask); + int qPy_pred, qPy_a, qPy_b; + + // qPy_pred + if (lc->first_qp_group || (!xQgBase && !yQgBase)) { + lc->first_qp_group = !lc->tu.is_cu_qp_delta_coded; + qPy_pred = s->sh.slice_qp; + } else { + qPy_pred = lc->qPy_pred; + } + + // qPy_a + if (availableA == 0) + qPy_a = qPy_pred; + else + qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width]; + + // qPy_b + if (availableB == 0) + qPy_b = qPy_pred; + else + qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width]; + + av_assert2(qPy_a >= -s->sps->qp_bd_offset && qPy_a < 52); + av_assert2(qPy_b >= -s->sps->qp_bd_offset && qPy_b < 52); + + return (qPy_a + qPy_b + 1) >> 1; +} + +void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase, int log2_cb_size) +{ + int qp_y = get_qPy_pred(s, xBase, yBase, log2_cb_size); + + if (s->HEVClc->tu.cu_qp_delta != 0) { + int off = s->sps->qp_bd_offset; + s->HEVClc->qp_y = FFUMOD(qp_y + s->HEVClc->tu.cu_qp_delta + 52 + 2 * off, + 52 + off) - off; + } else + s->HEVClc->qp_y = qp_y; +} + +static int get_qPy(HEVCContext *s, int xC, int yC) +{ + int log2_min_cb_size = s->sps->log2_min_cb_size; + int x = xC >> log2_min_cb_size; + int y = yC >> log2_min_cb_size; + return s->qp_y_tab[x + y * s->sps->min_cb_width]; +} + +static void copy_CTB(uint8_t *dst, const uint8_t *src, + int width, int height, int stride_dst, int stride_src) +{ + int i; + + for (i = 0; i < height; i++) { + memcpy(dst, src, width); + dst += stride_dst; + src += stride_src; + } +} + +#if defined(USE_SAO_SMALL_BUFFER) +static void copy_pixel(uint8_t *dst, const uint8_t *src, int pixel_shift) +{ + if (pixel_shift) + *(uint16_t *)dst = *(uint16_t *)src; + else + *dst = *src; + +} + +static void copy_vert(uint8_t *dst, const uint8_t *src, + int pixel_shift, int height, + int stride_dst, int stride_src) +{ + int i; + if (pixel_shift == 0) { + for (i = 0; i < height; i++) { + *dst = *src; + dst += stride_dst; + src += stride_src; + } + } else { + for (i = 0; i < height; i++) { + *(uint16_t *)dst = *(uint16_t *)src; + dst += stride_dst; + src += stride_src; + } + } +} + +static void copy_CTB_to_hv(HEVCContext *s, const uint8_t *src, + int stride_src, int x, int y, int width, int height, + int c_idx, int x_ctb, int y_ctb) +{ + int sh = s->sps->pixel_shift; + int w = s->sps->width >> s->sps->hshift[c_idx]; + int h = s->sps->height >> s->sps->vshift[c_idx]; + + /* copy horizontal edges */ + memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh), + src, width << sh); + memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh), + src + stride_src * (height - 1), width << sh); + + /* copy vertical edges */ + copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src); + + copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src); +} +#endif + +static void restore_tqb_pixels(HEVCContext *s, + uint8_t *src1, const uint8_t *dst1, + ptrdiff_t stride_src, ptrdiff_t stride_dst, + int x0, int y0, int width, int height, int c_idx) +{ + if ( s->pps->transquant_bypass_enable_flag || + (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) { + int x, y; + int min_pu_size = 1 << s->sps->log2_min_pu_size; + int hshift = s->sps->hshift[c_idx]; + int vshift = s->sps->vshift[c_idx]; + int x_min = ((x0 ) >> s->sps->log2_min_pu_size); + int y_min = ((y0 ) >> s->sps->log2_min_pu_size); + int x_max = ((x0 + width ) >> s->sps->log2_min_pu_size); + int y_max = ((y0 + height) >> s->sps->log2_min_pu_size); + int len = (min_pu_size >> hshift) << s->sps->pixel_shift; + for (y = y_min; y < y_max; y++) { + for (x = x_min; x < x_max; x++) { + if (s->is_pcm[y * s->sps->min_pu_width + x]) { + int n; + uint8_t *src = src1 + (((y - y0) << s->sps->log2_min_pu_size) >> vshift) * stride_src + ((((x - x0) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); + const uint8_t *dst = dst1 + (((y - y0) << s->sps->log2_min_pu_size) >> vshift) * stride_dst + ((((x - x0) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); + for (n = 0; n < (min_pu_size >> vshift); n++) { + memcpy(src, dst, len); + src += stride_src; + dst += stride_dst; + } + } + } + } + } +} + +#define CTB(tab, x, y) ((tab)[(y) * s->sps->ctb_width + (x)]) + +static void sao_filter_CTB(HEVCContext *s, int x, int y) +{ + int c_idx, c_count; + int edges[4]; // 0 left 1 top 2 right 3 bottom + int x_ctb = x >> s->sps->log2_ctb_size; + int y_ctb = y >> s->sps->log2_ctb_size; + int ctb_addr_rs = y_ctb * s->sps->ctb_width + x_ctb; + int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[ctb_addr_rs]; + SAOParams *sao = &CTB(s->sao, x_ctb, y_ctb); + // flags indicating unfilterable edges + uint8_t vert_edge[] = { 0, 0 }; + uint8_t horiz_edge[] = { 0, 0 }; + uint8_t diag_edge[] = { 0, 0, 0, 0 }; + uint8_t lfase = CTB(s->filter_slice_edges, x_ctb, y_ctb); + uint8_t no_tile_filter = s->pps->tiles_enabled_flag && + !s->pps->loop_filter_across_tiles_enabled_flag; + uint8_t restore = no_tile_filter || !lfase; + uint8_t left_tile_edge = 0; + uint8_t right_tile_edge = 0; + uint8_t up_tile_edge = 0; + uint8_t bottom_tile_edge = 0; + + edges[0] = x_ctb == 0; + edges[1] = y_ctb == 0; + edges[2] = x_ctb == s->sps->ctb_width - 1; + edges[3] = y_ctb == s->sps->ctb_height - 1; + + if (restore) { + if (!edges[0]) { + left_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]]; + vert_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge; + } + if (!edges[2]) { + right_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]]; + vert_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge; + } + if (!edges[1]) { + up_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]]; + horiz_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge; + } + if (!edges[3]) { + bottom_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs + s->sps->ctb_width]]; + horiz_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge; + } + if (!edges[0] && !edges[1]) { + diag_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge; + } + if (!edges[1] && !edges[2]) { + diag_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge; + } + if (!edges[2] && !edges[3]) { + diag_edge[2] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge; + } + if (!edges[0] && !edges[3]) { + diag_edge[3] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge; + } + } + + c_count = (s->sps->chroma_format_idc != 0) ? 3 : 1; + for (c_idx = 0; c_idx < c_count; c_idx++) { + int x0 = x >> s->sps->hshift[c_idx]; + int y0 = y >> s->sps->vshift[c_idx]; + int stride_src = s->frame->linesize[c_idx]; + int ctb_size_h = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx]; + int ctb_size_v = (1 << (s->sps->log2_ctb_size)) >> s->sps->vshift[c_idx]; + int width = FFMIN(ctb_size_h, (s->sps->width >> s->sps->hshift[c_idx]) - x0); + int height = FFMIN(ctb_size_v, (s->sps->height >> s->sps->vshift[c_idx]) - y0); + uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->sps->pixel_shift)]; +#if defined(USE_SAO_SMALL_BUFFER) + int stride_dst = ((1 << (s->sps->log2_ctb_size)) + 2) << s->sps->pixel_shift; + uint8_t *dst = s->sao_pixel_buffer + (1 * stride_dst) + (1 << s->sps->pixel_shift); +#else + int stride_dst = s->sao_frame->linesize[c_idx]; + uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride_dst + (x0 << s->sps->pixel_shift)]; +#endif + + switch (sao->type_idx[c_idx]) { + case SAO_BAND: + copy_CTB(dst, src, width << s->sps->pixel_shift, height, stride_dst, stride_src); +#if defined(USE_SAO_SMALL_BUFFER) + copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx, + x_ctb, y_ctb); +#endif + s->hevcdsp.sao_band_filter(src, dst, + stride_src, stride_dst, + sao, + edges, width, + height, c_idx BIT_DEPTH_ARG2(s->sps->bit_depth)); + restore_tqb_pixels(s, src, dst, stride_src, stride_dst, + x, y, width, height, c_idx); + sao->type_idx[c_idx] = SAO_APPLIED; + break; + case SAO_EDGE: + { +#if defined(USE_SAO_SMALL_BUFFER) + int w = s->sps->width >> s->sps->hshift[c_idx]; + int h = s->sps->height >> s->sps->vshift[c_idx]; + int left_edge = edges[0]; + int top_edge = edges[1]; + int right_edge = edges[2]; + int bottom_edge = edges[3]; + int sh = s->sps->pixel_shift; + int left_pixels, right_pixels; + + if (!top_edge) { + int left = 1 - left_edge; + int right = 1 - right_edge; + const uint8_t *src1[2]; + uint8_t *dst1; + int src_idx, pos; + + dst1 = dst - stride_dst - (left << sh); + src1[0] = src - stride_src - (left << sh); + src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh); + pos = 0; + if (left) { + src_idx = (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] == + SAO_APPLIED); + copy_pixel(dst1, src1[src_idx], sh); + pos += (1 << sh); + } + src_idx = (CTB(s->sao, x_ctb, y_ctb-1).type_idx[c_idx] == + SAO_APPLIED); + memcpy(dst1 + pos, src1[src_idx] + pos, width << sh); + if (right) { + pos += width << sh; + src_idx = (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] == + SAO_APPLIED); + copy_pixel(dst1 + pos, src1[src_idx] + pos, sh); + } + } + if (!bottom_edge) { + int left = 1 - left_edge; + int right = 1 - right_edge; + const uint8_t *src1[2]; + uint8_t *dst1; + int src_idx, pos; + + dst1 = dst + height * stride_dst - (left << sh); + src1[0] = src + height * stride_src - (left << sh); + src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh); + pos = 0; + if (left) { + src_idx = (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] == + SAO_APPLIED); + copy_pixel(dst1, src1[src_idx], sh); + pos += (1 << sh); + } + src_idx = (CTB(s->sao, x_ctb, y_ctb+1).type_idx[c_idx] == + SAO_APPLIED); + memcpy(dst1 + pos, src1[src_idx] + pos, width << sh); + if (right) { + pos += width << sh; + src_idx = (CTB(s->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] == + SAO_APPLIED); + copy_pixel(dst1 + pos, src1[src_idx] + pos, sh); + } + } + left_pixels = 0; + if (!left_edge) { + if (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { + copy_vert(dst - (1 << sh), + s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh), + sh, height, stride_dst, 1 << sh); + } else { + left_pixels = 1; + } + } + right_pixels = 0; + if (!right_edge) { + if (CTB(s->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { + copy_vert(dst + (width << sh), + s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh), + sh, height, stride_dst, 1 << sh); + } else { + right_pixels = 1; + } + } + + copy_CTB(dst - (left_pixels << sh), + src - (left_pixels << sh), + (width + left_pixels + right_pixels) << sh, + height, stride_dst, stride_src); + + copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx, + x_ctb, y_ctb); +#else + uint8_t left_pixels; + /* get the CTB edge pixels from the SAO pixel buffer */ + left_pixels = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] != SAO_APPLIED); + if (!edges[1]) { + uint8_t top_left = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] != SAO_APPLIED); + uint8_t top_right = !edges[2] && (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] != SAO_APPLIED); + if (CTB(s->sao, x_ctb , y_ctb-1).type_idx[c_idx] == 0) + memcpy( dst - stride_dst - (top_left << s->sps->pixel_shift), + src - stride_src - (top_left << s->sps->pixel_shift), + (top_left + width + top_right) << s->sps->pixel_shift); + else { + if (top_left) + memcpy( dst - stride_dst - (1 << s->sps->pixel_shift), + src - stride_src - (1 << s->sps->pixel_shift), + 1 << s->sps->pixel_shift); + if(top_right) + memcpy( dst - stride_dst + (width << s->sps->pixel_shift), + src - stride_src + (width << s->sps->pixel_shift), + 1 << s->sps->pixel_shift); + } + } + if (!edges[3]) { // bottom and bottom right + uint8_t bottom_left = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] != SAO_APPLIED); + memcpy( dst + height * stride_dst - (bottom_left << s->sps->pixel_shift), + src + height * stride_src - (bottom_left << s->sps->pixel_shift), + (width + 1 + bottom_left) << s->sps->pixel_shift); + } + copy_CTB(dst - (left_pixels << s->sps->pixel_shift), + src - (left_pixels << s->sps->pixel_shift), + (width + 1 + left_pixels) << s->sps->pixel_shift, height, stride_dst, stride_src); +#endif + /* XXX: could handle the restoration here to simplify the + DSP functions */ + s->hevcdsp.sao_edge_filter[restore](src, dst, + stride_src, stride_dst, + sao, + edges, width, + height, c_idx, + vert_edge, + horiz_edge, + diag_edge BIT_DEPTH_ARG2(s->sps->bit_depth)); + restore_tqb_pixels(s, src, dst, stride_src, stride_dst, + x, y, width, height, c_idx); + sao->type_idx[c_idx] = SAO_APPLIED; + break; + } + } + } +} + +static int get_pcm(HEVCContext *s, int x, int y) +{ + int log2_min_pu_size = s->sps->log2_min_pu_size; + int x_pu, y_pu; + + if (x < 0 || y < 0) + return 2; + + x_pu = x >> log2_min_pu_size; + y_pu = y >> log2_min_pu_size; + + if (x_pu >= s->sps->min_pu_width || y_pu >= s->sps->min_pu_height) + return 2; + return s->is_pcm[y_pu * s->sps->min_pu_width + x_pu]; +} + +#define TC_CALC(qp, bs) \ + tctable[av_clip((qp) + DEFAULT_INTRA_TC_OFFSET * ((bs) - 1) + \ + (tc_offset >> 1 << 1), \ + 0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)] + +static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0) +{ + uint8_t *src; + int x, y; + int chroma, beta; + int32_t c_tc[2], tc[2]; + uint8_t no_p[2] = { 0 }; + uint8_t no_q[2] = { 0 }; + + int log2_ctb_size = s->sps->log2_ctb_size; + int x_end, x_end2, y_end; + int ctb_size = 1 << log2_ctb_size; + int ctb = (x0 >> log2_ctb_size) + + (y0 >> log2_ctb_size) * s->sps->ctb_width; + int cur_tc_offset = s->deblock[ctb].tc_offset; + int cur_beta_offset = s->deblock[ctb].beta_offset; + int left_tc_offset, left_beta_offset; + int tc_offset, beta_offset; + int pcmf = (s->sps->pcm_enabled_flag && + s->sps->pcm.loop_filter_disable_flag) || + s->pps->transquant_bypass_enable_flag; + int bit_depth = s->sps->bit_depth; + + if (x0) { + left_tc_offset = s->deblock[ctb - 1].tc_offset; + left_beta_offset = s->deblock[ctb - 1].beta_offset; + } else { + left_tc_offset = 0; + left_beta_offset = 0; + } + + x_end = x0 + ctb_size; + if (x_end > s->sps->width) + x_end = s->sps->width; + y_end = y0 + ctb_size; + if (y_end > s->sps->height) + y_end = s->sps->height; + + tc_offset = cur_tc_offset; + beta_offset = cur_beta_offset; + + x_end2 = x_end; + if (x_end2 != s->sps->width) + x_end2 -= 8; + for (y = y0; y < y_end; y += 8) { + // vertical filtering luma + for (x = x0 ? x0 : 8; x < x_end; x += 8) { + const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2]; + const int bs1 = s->vertical_bs[(x + (y + 4) * s->bs_width) >> 2]; + if (bs0 || bs1) { + const int qp = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1; + + beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; + + tc[0] = bs0 ? TC_CALC(qp, bs0) : 0; + tc[1] = bs1 ? TC_CALC(qp, bs1) : 0; + src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->sps->pixel_shift)]; + if (pcmf) { + no_p[0] = get_pcm(s, x - 1, y); + no_p[1] = get_pcm(s, x - 1, y + 4); + no_q[0] = get_pcm(s, x, y); + no_q[1] = get_pcm(s, x, y + 4); + s->hevcdsp.hevc_v_loop_filter_luma_c(src, + s->frame->linesize[LUMA], + beta, tc, no_p, no_q BIT_DEPTH_ARG); + } else + s->hevcdsp.hevc_v_loop_filter_luma(src, + s->frame->linesize[LUMA], + beta, tc, no_p, no_q BIT_DEPTH_ARG); + } + } + + if(!y) + continue; + + // horizontal filtering luma + for (x = x0 ? x0 - 8 : 0; x < x_end2; x += 8) { + const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2]; + const int bs1 = s->horizontal_bs[((x + 4) + y * s->bs_width) >> 2]; + if (bs0 || bs1) { + const int qp = (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1; + + tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset; + beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset; + + beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; + tc[0] = bs0 ? TC_CALC(qp, bs0) : 0; + tc[1] = bs1 ? TC_CALC(qp, bs1) : 0; + src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->sps->pixel_shift)]; + if (pcmf) { + no_p[0] = get_pcm(s, x, y - 1); + no_p[1] = get_pcm(s, x + 4, y - 1); + no_q[0] = get_pcm(s, x, y); + no_q[1] = get_pcm(s, x + 4, y); + s->hevcdsp.hevc_h_loop_filter_luma_c(src, + s->frame->linesize[LUMA], + beta, tc, no_p, no_q BIT_DEPTH_ARG); + } else + s->hevcdsp.hevc_h_loop_filter_luma(src, + s->frame->linesize[LUMA], + beta, tc, no_p, no_q BIT_DEPTH_ARG); + } + } + } + + if (s->sps->chroma_format_idc != 0) { + for (chroma = 1; chroma <= 2; chroma++) { + int h = 1 << s->sps->hshift[chroma]; + int v = 1 << s->sps->vshift[chroma]; + + // vertical filtering chroma + for (y = y0; y < y_end; y += (8 * v)) { + for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) { + const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2]; + const int bs1 = s->vertical_bs[(x + (y + (4 * v)) * s->bs_width) >> 2]; + + if ((bs0 == 2) || (bs1 == 2)) { + const int qp0 = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1; + const int qp1 = (get_qPy(s, x - 1, y + (4 * v)) + get_qPy(s, x, y + (4 * v)) + 1) >> 1; + + c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0; + c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0; + src = &s->frame->data[chroma][(y >> s->sps->vshift[chroma]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[chroma]) << s->sps->pixel_shift)]; + if (pcmf) { + no_p[0] = get_pcm(s, x - 1, y); + no_p[1] = get_pcm(s, x - 1, y + (4 * v)); + no_q[0] = get_pcm(s, x, y); + no_q[1] = get_pcm(s, x, y + (4 * v)); + s->hevcdsp.hevc_v_loop_filter_chroma_c(src, + s->frame->linesize[chroma], + c_tc, no_p, no_q BIT_DEPTH_ARG); + } else + s->hevcdsp.hevc_v_loop_filter_chroma(src, + s->frame->linesize[chroma], + c_tc, no_p, no_q BIT_DEPTH_ARG); + } + } + + if(!y) + continue; + + // horizontal filtering chroma + tc_offset = x0 ? left_tc_offset : cur_tc_offset; + x_end2 = x_end; + if (x_end != s->sps->width) + x_end2 = x_end - 8 * h; + for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) { + const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2]; + const int bs1 = s->horizontal_bs[((x + 4 * h) + y * s->bs_width) >> 2]; + if ((bs0 == 2) || (bs1 == 2)) { + const int qp0 = bs0 == 2 ? (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1 : 0; + const int qp1 = bs1 == 2 ? (get_qPy(s, x + (4 * h), y - 1) + get_qPy(s, x + (4 * h), y) + 1) >> 1 : 0; + + c_tc[0] = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset) : 0; + c_tc[1] = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0; + src = &s->frame->data[chroma][(y >> s->sps->vshift[1]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[1]) << s->sps->pixel_shift)]; + if (pcmf) { + no_p[0] = get_pcm(s, x, y - 1); + no_p[1] = get_pcm(s, x + (4 * h), y - 1); + no_q[0] = get_pcm(s, x, y); + no_q[1] = get_pcm(s, x + (4 * h), y); + s->hevcdsp.hevc_h_loop_filter_chroma_c(src, + s->frame->linesize[chroma], + c_tc, no_p, no_q BIT_DEPTH_ARG); + } else + s->hevcdsp.hevc_h_loop_filter_chroma(src, + s->frame->linesize[chroma], + c_tc, no_p, no_q BIT_DEPTH_ARG); + } + } + } + } + } /* chroma_format_idc != 0 */ +} + +#ifdef USE_PRED +static int boundary_strength(HEVCContext *s, MvField *curr, MvField *neigh, + RefPicList *neigh_refPicList) +{ + if (curr->pred_flag == PF_BI && neigh->pred_flag == PF_BI) { + // same L0 and L1 + if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] && + s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] && + neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) { + if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 || + FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) && + (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 || + FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4)) + return 1; + else + return 0; + } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] && + neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) { + if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 || + FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) + return 1; + else + return 0; + } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] && + neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) { + if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 || + FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4) + return 1; + else + return 0; + } else { + return 1; + } + } else if ((curr->pred_flag != PF_BI) && (neigh->pred_flag != PF_BI)){ // 1 MV + Mv A, B; + int ref_A, ref_B; + + if (curr->pred_flag & 1) { + A = curr->mv[0]; + ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]]; + } else { + A = curr->mv[1]; + ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]]; + } + + if (neigh->pred_flag & 1) { + B = neigh->mv[0]; + ref_B = neigh_refPicList[0].list[neigh->ref_idx[0]]; + } else { + B = neigh->mv[1]; + ref_B = neigh_refPicList[1].list[neigh->ref_idx[1]]; + } + + if (ref_A == ref_B) { + if (FFABS(A.x - B.x) >= 4 || FFABS(A.y - B.y) >= 4) + return 1; + else + return 0; + } else + return 1; + } + return 1; +} +#endif + +void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, + int log2_trafo_size) +{ + HEVCLocalContext *lc = s->HEVClc; + int log2_min_pu_size = s->sps->log2_min_pu_size; + int log2_min_tu_size = s->sps->log2_min_tb_size; + int min_pu_width = s->sps->min_pu_width; + int min_tu_width = s->sps->min_tb_width; +#ifdef USE_PRED + MvField *tab_mvf = s->ref->tab_mvf; + int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width + + (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; + int j; +#endif + int boundary_upper, boundary_left; + int i, bs; + + boundary_upper = y0 > 0 && !(y0 & 7); + if (boundary_upper && + ((!s->sh.slice_loop_filter_across_slices_enabled_flag && + lc->boundary_flags & BOUNDARY_UPPER_SLICE && + (y0 % (1 << s->sps->log2_ctb_size)) == 0) || + (!s->pps->loop_filter_across_tiles_enabled_flag && + lc->boundary_flags & BOUNDARY_UPPER_TILE && + (y0 % (1 << s->sps->log2_ctb_size)) == 0))) + boundary_upper = 0; + + if (boundary_upper) { +#ifdef USE_PRED + RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ? + ff_hevc_get_ref_list(s, s->ref, x0, y0 - 1) : + s->ref->refPicList; + int yp_pu = (y0 - 1) >> log2_min_pu_size; + int yq_pu = y0 >> log2_min_pu_size; + int yp_tu = (y0 - 1) >> log2_min_tu_size; + int yq_tu = y0 >> log2_min_tu_size; + + for (i = 0; i < (1 << log2_trafo_size); i += 4) { + int x_pu = (x0 + i) >> log2_min_pu_size; + int x_tu = (x0 + i) >> log2_min_tu_size; + MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu]; + MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu]; + uint8_t top_cbf_luma = s->cbf_luma[yp_tu * min_tu_width + x_tu]; + uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu]; + + if (curr->pred_flag == PF_INTRA || top->pred_flag == PF_INTRA) + bs = 2; + else if (curr_cbf_luma || top_cbf_luma) + bs = 1; + else + bs = boundary_strength(s, curr, top, rpl_top); + s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs; + } +#else + for (i = 0; i < (1 << log2_trafo_size); i += 4) { + s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = 2; + } +#endif + } + + // bs for vertical TU boundaries + boundary_left = x0 > 0 && !(x0 & 7); + if (boundary_left && + ((!s->sh.slice_loop_filter_across_slices_enabled_flag && + lc->boundary_flags & BOUNDARY_LEFT_SLICE && + (x0 % (1 << s->sps->log2_ctb_size)) == 0) || + (!s->pps->loop_filter_across_tiles_enabled_flag && + lc->boundary_flags & BOUNDARY_LEFT_TILE && + (x0 % (1 << s->sps->log2_ctb_size)) == 0))) + boundary_left = 0; + + if (boundary_left) { +#ifdef USE_PRED + RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ? + ff_hevc_get_ref_list(s, s->ref, x0 - 1, y0) : + s->ref->refPicList; + int xp_pu = (x0 - 1) >> log2_min_pu_size; + int xq_pu = x0 >> log2_min_pu_size; + int xp_tu = (x0 - 1) >> log2_min_tu_size; + int xq_tu = x0 >> log2_min_tu_size; + + for (i = 0; i < (1 << log2_trafo_size); i += 4) { + int y_pu = (y0 + i) >> log2_min_pu_size; + int y_tu = (y0 + i) >> log2_min_tu_size; + MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu]; + MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu]; + uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu]; + uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu]; + + if (curr->pred_flag == PF_INTRA || left->pred_flag == PF_INTRA) + bs = 2; + else if (curr_cbf_luma || left_cbf_luma) + bs = 1; + else + bs = boundary_strength(s, curr, left, rpl_left); + s->vertical_bs[(x0 + (y0 + i) * s->bs_width) >> 2] = bs; + } +#else + for (i = 0; i < (1 << log2_trafo_size); i += 4) { + s->vertical_bs[(x0 + (y0 + i) * s->bs_width) >> 2] = 2; + } +#endif + } + +#ifdef USE_PRED + if (log2_trafo_size > log2_min_pu_size && !is_intra) { + RefPicList *rpl = s->ref->refPicList; + + // bs for TU internal horizontal PU boundaries + for (j = 8; j < (1 << log2_trafo_size); j += 8) { + int yp_pu = (y0 + j - 1) >> log2_min_pu_size; + int yq_pu = (y0 + j) >> log2_min_pu_size; + + for (i = 0; i < (1 << log2_trafo_size); i += 4) { + int x_pu = (x0 + i) >> log2_min_pu_size; + MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu]; + MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu]; + + bs = boundary_strength(s, curr, top, rpl); + s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs; + } + } + + // bs for TU internal vertical PU boundaries + for (j = 0; j < (1 << log2_trafo_size); j += 4) { + int y_pu = (y0 + j) >> log2_min_pu_size; + + for (i = 8; i < (1 << log2_trafo_size); i += 8) { + int xp_pu = (x0 + i - 1) >> log2_min_pu_size; + int xq_pu = (x0 + i) >> log2_min_pu_size; + MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu]; + MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu]; + + bs = boundary_strength(s, curr, left, rpl); + s->vertical_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs; + } + } + } +#endif +} + +#undef LUMA +#undef CB +#undef CR + +void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size) +{ + int x_end = x >= s->sps->width - ctb_size; + deblocking_filter_CTB(s, x, y); + if (s->sps->sao_enabled) { + int y_end = y >= s->sps->height - ctb_size; + if (y && x) + sao_filter_CTB(s, x - ctb_size, y - ctb_size); + if (x && y_end) + sao_filter_CTB(s, x - ctb_size, y); + if (y && x_end) { + sao_filter_CTB(s, x, y - ctb_size); + if (s->threads_type & FF_THREAD_FRAME ) + ff_thread_report_progress(&s->ref->tf, y, 0); + } + if (x_end && y_end) { + sao_filter_CTB(s, x , y); + if (s->threads_type & FF_THREAD_FRAME ) + ff_thread_report_progress(&s->ref->tf, y + ctb_size, 0); + } + } else if (s->threads_type & FF_THREAD_FRAME && x_end) + ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0); +} + +void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size) +{ + int x_end = x_ctb >= s->sps->width - ctb_size; + int y_end = y_ctb >= s->sps->height - ctb_size; + if (y_ctb && x_ctb) + ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size); + if (y_ctb && x_end) + ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size, ctb_size); + if (x_ctb && y_end) + ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb, ctb_size); +} diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c new file mode 100644 index 0000000..a8aade8 --- /dev/null +++ b/libavcodec/hevc_mvs.c @@ -0,0 +1,777 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 Anand Meher Kotra + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hevc.h" + +#ifdef USE_PRED +static const uint8_t l0_l1_cand_idx[12][2] = { + { 0, 1, }, + { 1, 0, }, + { 0, 2, }, + { 2, 0, }, + { 1, 2, }, + { 2, 1, }, + { 0, 3, }, + { 3, 0, }, + { 1, 3, }, + { 3, 1, }, + { 2, 3, }, + { 3, 2, }, +}; +#endif + +void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH) +{ + HEVCLocalContext *lc = s->HEVClc; + int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1); + int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1); + + lc->na.cand_up = (lc->ctb_up_flag || y0b); + lc->na.cand_left = (lc->ctb_left_flag || x0b); + lc->na.cand_up_left = (!x0b && !y0b) ? lc->ctb_up_left_flag : lc->na.cand_left && lc->na.cand_up; + lc->na.cand_up_right_sap = + ((x0b + nPbW) == (1 << s->sps->log2_ctb_size)) ? + lc->ctb_up_right_flag && !y0b : lc->na.cand_up; + lc->na.cand_up_right = + lc->na.cand_up_right_sap + && (x0 + nPbW) < lc->end_of_tiles_x; + lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left; +} + +#ifdef USE_PRED +/* + * 6.4.1 Derivation process for z-scan order block availability + */ +static av_always_inline int z_scan_block_avail(HEVCContext *s, int xCurr, int yCurr, + int xN, int yN) +{ +#define MIN_TB_ADDR_ZS(x, y) \ + s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)] + + int xCurr_ctb = xCurr >> s->sps->log2_ctb_size; + int yCurr_ctb = yCurr >> s->sps->log2_ctb_size; + int xN_ctb = xN >> s->sps->log2_ctb_size; + int yN_ctb = yN >> s->sps->log2_ctb_size; + if( yN_ctb < yCurr_ctb || xN_ctb < xCurr_ctb ) + return 1; + else { + int Curr = MIN_TB_ADDR_ZS((xCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask, + (yCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask); + int N = MIN_TB_ADDR_ZS((xN >> s->sps->log2_min_tb_size) & s->sps->tb_mask, + (yN >> s->sps->log2_min_tb_size) & s->sps->tb_mask); + return N <= Curr; + } +} + +//check if the two luma locations belong to the same mostion estimation region +static av_always_inline int is_diff_mer(HEVCContext *s, int xN, int yN, int xP, int yP) +{ + uint8_t plevel = s->pps->log2_parallel_merge_level; + + return xN >> plevel == xP >> plevel && + yN >> plevel == yP >> plevel; +} + +#define MATCH_MV(x) (AV_RN32A(&A.x) == AV_RN32A(&B.x)) +#define MATCH(x) (A.x == B.x) + +// check if the mv's and refidx are the same between A and B +static av_always_inline int compare_mv_ref_idx(struct MvField A, struct MvField B) +{ + int a_pf = A.pred_flag; + int b_pf = B.pred_flag; + if (a_pf == b_pf) { + if (a_pf == PF_BI) { + return MATCH(ref_idx[0]) && MATCH_MV(mv[0]) && + MATCH(ref_idx[1]) && MATCH_MV(mv[1]); + } else if (a_pf == PF_L0) { + return MATCH(ref_idx[0]) && MATCH_MV(mv[0]); + } else if (a_pf == PF_L1) { + return MATCH(ref_idx[1]) && MATCH_MV(mv[1]); + } + } + return 0; +} + +static av_always_inline void mv_scale(Mv *dst, Mv *src, int td, int tb) +{ + int tx, scale_factor; + + td = av_clip_int8(td); + tb = av_clip_int8(tb); + tx = (0x4000 + abs(td / 2)) / td; + scale_factor = av_clip((tb * tx + 32) >> 6, -4096, 4095); + dst->x = av_clip_int16((scale_factor * src->x + 127 + + (scale_factor * src->x < 0)) >> 8); + dst->y = av_clip_int16((scale_factor * src->y + 127 + + (scale_factor * src->y < 0)) >> 8); +} + +static int check_mvset(Mv *mvLXCol, Mv *mvCol, + int colPic, int poc, + RefPicList *refPicList, int X, int refIdxLx, + RefPicList *refPicList_col, int listCol, int refidxCol) +{ + int cur_lt = refPicList[X].isLongTerm[refIdxLx]; + int col_lt = refPicList_col[listCol].isLongTerm[refidxCol]; + int col_poc_diff, cur_poc_diff; + + if (cur_lt != col_lt) { + mvLXCol->x = 0; + mvLXCol->y = 0; + return 0; + } + + col_poc_diff = colPic - refPicList_col[listCol].list[refidxCol]; + cur_poc_diff = poc - refPicList[X].list[refIdxLx]; + + if (cur_lt || col_poc_diff == cur_poc_diff || !col_poc_diff) { + mvLXCol->x = mvCol->x; + mvLXCol->y = mvCol->y; + } else { + mv_scale(mvLXCol, mvCol, col_poc_diff, cur_poc_diff); + } + return 1; +} + +#define CHECK_MVSET(l) \ + check_mvset(mvLXCol, temp_col.mv + l, \ + colPic, s->poc, \ + refPicList, X, refIdxLx, \ + refPicList_col, L ## l, temp_col.ref_idx[l]) + +// derive the motion vectors section 8.5.3.1.8 +static int derive_temporal_colocated_mvs(HEVCContext *s, MvField temp_col, + int refIdxLx, Mv *mvLXCol, int X, + int colPic, RefPicList *refPicList_col) +{ + RefPicList *refPicList = s->ref->refPicList; + + if (temp_col.pred_flag == PF_INTRA) + return 0; + + if (!(temp_col.pred_flag & PF_L0)) + return CHECK_MVSET(1); + else if (temp_col.pred_flag == PF_L0) + return CHECK_MVSET(0); + else if (temp_col.pred_flag == PF_BI) { + int check_diffpicount = 0; + int i, j; + for (j = 0; j < 2; j++) { + for (i = 0; i < refPicList[j].nb_refs; i++) { + if (refPicList[j].list[i] > s->poc) { + check_diffpicount++; + break; + } + } + } + if (!check_diffpicount) { + if (X==0) + return CHECK_MVSET(0); + else + return CHECK_MVSET(1); + } else { + if (s->sh.collocated_list == L1) + return CHECK_MVSET(0); + else + return CHECK_MVSET(1); + } + } + + return 0; +} + +#define TAB_MVF(x, y) \ + tab_mvf[(y) * min_pu_width + x] + +#define TAB_MVF_PU(v) \ + TAB_MVF(((x ## v) >> s->sps->log2_min_pu_size), \ + ((y ## v) >> s->sps->log2_min_pu_size)) + +#define DERIVE_TEMPORAL_COLOCATED_MVS \ + derive_temporal_colocated_mvs(s, temp_col, \ + refIdxLx, mvLXCol, X, colPic, \ + ff_hevc_get_ref_list(s, ref, x, y)) + +/* + * 8.5.3.1.7 temporal luma motion vector prediction + */ +static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH, int refIdxLx, + Mv *mvLXCol, int X) +{ + MvField *tab_mvf; + MvField temp_col; + int x, y, x_pu, y_pu; + int min_pu_width = s->sps->min_pu_width; + int availableFlagLXCol = 0; + int colPic; + + HEVCFrame *ref = s->ref->collocated_ref; + + if (!ref) { + memset(mvLXCol, 0, sizeof(*mvLXCol)); + return 0; + } + + tab_mvf = ref->tab_mvf; + colPic = ref->poc; + + //bottom right collocated motion vector + x = x0 + nPbW; + y = y0 + nPbH; + + if (tab_mvf && + (y0 >> s->sps->log2_ctb_size) == (y >> s->sps->log2_ctb_size) && + y < s->sps->height && + x < s->sps->width) { + x &= ~15; + y &= ~15; + if (s->threads_type == FF_THREAD_FRAME) + ff_thread_await_progress(&ref->tf, y, 0); + x_pu = x >> s->sps->log2_min_pu_size; + y_pu = y >> s->sps->log2_min_pu_size; + temp_col = TAB_MVF(x_pu, y_pu); + availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS; + } + + // derive center collocated motion vector + if (tab_mvf && !availableFlagLXCol) { + x = x0 + (nPbW >> 1); + y = y0 + (nPbH >> 1); + x &= ~15; + y &= ~15; + if (s->threads_type == FF_THREAD_FRAME) + ff_thread_await_progress(&ref->tf, y, 0); + x_pu = x >> s->sps->log2_min_pu_size; + y_pu = y >> s->sps->log2_min_pu_size; + temp_col = TAB_MVF(x_pu, y_pu); + availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS; + } + return availableFlagLXCol; +} + +#define AVAILABLE(cand, v) \ + (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA)) + +#define PRED_BLOCK_AVAILABLE(v) \ + z_scan_block_avail(s, x0, y0, x ## v, y ## v) + +#define COMPARE_MV_REFIDX(a, b) \ + compare_mv_ref_idx(TAB_MVF_PU(a), TAB_MVF_PU(b)) + +/* + * 8.5.3.1.2 Derivation process for spatial merging candidates + */ +static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0, + int nPbW, int nPbH, + int log2_cb_size, + int singleMCLFlag, int part_idx, + int merge_idx, + struct MvField mergecandlist[]) +{ + HEVCLocalContext *lc = s->HEVClc; + RefPicList *refPicList = s->ref->refPicList; + MvField *tab_mvf = s->ref->tab_mvf; + + const int min_pu_width = s->sps->min_pu_width; + + const int cand_bottom_left = lc->na.cand_bottom_left; + const int cand_left = lc->na.cand_left; + const int cand_up_left = lc->na.cand_up_left; + const int cand_up = lc->na.cand_up; + const int cand_up_right = lc->na.cand_up_right_sap; + + const int xA1 = x0 - 1; + const int yA1 = y0 + nPbH - 1; + + const int xB1 = x0 + nPbW - 1; + const int yB1 = y0 - 1; + + const int xB0 = x0 + nPbW; + const int yB0 = y0 - 1; + + const int xA0 = x0 - 1; + const int yA0 = y0 + nPbH; + + const int xB2 = x0 - 1; + const int yB2 = y0 - 1; + + const int nb_refs = (s->sh.slice_type == P_SLICE) ? + s->sh.nb_refs[0] : FFMIN(s->sh.nb_refs[0], s->sh.nb_refs[1]); + + int zero_idx = 0; + + int nb_merge_cand = 0; + int nb_orig_merge_cand = 0; + + int is_available_a0; + int is_available_a1; + int is_available_b0; + int is_available_b1; + int is_available_b2; + + + if (!singleMCLFlag && part_idx == 1 && + (lc->cu.part_mode == PART_Nx2N || + lc->cu.part_mode == PART_nLx2N || + lc->cu.part_mode == PART_nRx2N) || + is_diff_mer(s, xA1, yA1, x0, y0)) { + is_available_a1 = 0; + } else { + is_available_a1 = AVAILABLE(cand_left, A1); + if (is_available_a1) { + mergecandlist[nb_merge_cand] = TAB_MVF_PU(A1); + if (merge_idx == 0) + return; + nb_merge_cand++; + } + } + + if (!singleMCLFlag && part_idx == 1 && + (lc->cu.part_mode == PART_2NxN || + lc->cu.part_mode == PART_2NxnU || + lc->cu.part_mode == PART_2NxnD) || + is_diff_mer(s, xB1, yB1, x0, y0)) { + is_available_b1 = 0; + } else { + is_available_b1 = AVAILABLE(cand_up, B1); + if (is_available_b1 && + !(is_available_a1 && COMPARE_MV_REFIDX(B1, A1))) { + mergecandlist[nb_merge_cand] = TAB_MVF_PU(B1); + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + } + + // above right spatial merge candidate + is_available_b0 = AVAILABLE(cand_up_right, B0) && + xB0 < s->sps->width && + PRED_BLOCK_AVAILABLE(B0) && + !is_diff_mer(s, xB0, yB0, x0, y0); + + if (is_available_b0 && + !(is_available_b1 && COMPARE_MV_REFIDX(B0, B1))) { + mergecandlist[nb_merge_cand] = TAB_MVF_PU(B0); + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + + // left bottom spatial merge candidate + is_available_a0 = AVAILABLE(cand_bottom_left, A0) && + yA0 < s->sps->height && + PRED_BLOCK_AVAILABLE(A0) && + !is_diff_mer(s, xA0, yA0, x0, y0); + + if (is_available_a0 && + !(is_available_a1 && COMPARE_MV_REFIDX(A0, A1))) { + mergecandlist[nb_merge_cand] = TAB_MVF_PU(A0); + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + + // above left spatial merge candidate + is_available_b2 = AVAILABLE(cand_up_left, B2) && + !is_diff_mer(s, xB2, yB2, x0, y0); + + if (is_available_b2 && + !(is_available_a1 && COMPARE_MV_REFIDX(B2, A1)) && + !(is_available_b1 && COMPARE_MV_REFIDX(B2, B1)) && + nb_merge_cand != 4) { + mergecandlist[nb_merge_cand] = TAB_MVF_PU(B2); + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + + // temporal motion vector candidate + if (s->sh.slice_temporal_mvp_enabled_flag && + nb_merge_cand < s->sh.max_num_merge_cand) { + Mv mv_l0_col = { 0 }, mv_l1_col = { 0 }; + int available_l0 = temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH, + 0, &mv_l0_col, 0); + int available_l1 = (s->sh.slice_type == B_SLICE) ? + temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH, + 0, &mv_l1_col, 1) : 0; + + if (available_l0 || available_l1) { + mergecandlist[nb_merge_cand].pred_flag = available_l0 + (available_l1 << 1); + AV_ZERO16(mergecandlist[nb_merge_cand].ref_idx); + mergecandlist[nb_merge_cand].mv[0] = mv_l0_col; + mergecandlist[nb_merge_cand].mv[1] = mv_l1_col; + + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + } + + nb_orig_merge_cand = nb_merge_cand; + + // combined bi-predictive merge candidates (applies for B slices) + if (s->sh.slice_type == B_SLICE && nb_orig_merge_cand > 1 && + nb_orig_merge_cand < s->sh.max_num_merge_cand) { + int comb_idx = 0; + + for (comb_idx = 0; nb_merge_cand < s->sh.max_num_merge_cand && + comb_idx < nb_orig_merge_cand * (nb_orig_merge_cand - 1); comb_idx++) { + int l0_cand_idx = l0_l1_cand_idx[comb_idx][0]; + int l1_cand_idx = l0_l1_cand_idx[comb_idx][1]; + MvField l0_cand = mergecandlist[l0_cand_idx]; + MvField l1_cand = mergecandlist[l1_cand_idx]; + + if ((l0_cand.pred_flag & PF_L0) && (l1_cand.pred_flag & PF_L1) && + (refPicList[0].list[l0_cand.ref_idx[0]] != + refPicList[1].list[l1_cand.ref_idx[1]] || + AV_RN32A(&l0_cand.mv[0]) != AV_RN32A(&l1_cand.mv[1]))) { + mergecandlist[nb_merge_cand].ref_idx[0] = l0_cand.ref_idx[0]; + mergecandlist[nb_merge_cand].ref_idx[1] = l1_cand.ref_idx[1]; + mergecandlist[nb_merge_cand].pred_flag = PF_BI; + AV_COPY32(&mergecandlist[nb_merge_cand].mv[0], &l0_cand.mv[0]); + AV_COPY32(&mergecandlist[nb_merge_cand].mv[1], &l1_cand.mv[1]); + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + } + } + } + + // append Zero motion vector candidates + while (nb_merge_cand < s->sh.max_num_merge_cand) { + mergecandlist[nb_merge_cand].pred_flag = PF_L0 + ((s->sh.slice_type == B_SLICE) << 1); + AV_ZERO32(mergecandlist[nb_merge_cand].mv + 0); + AV_ZERO32(mergecandlist[nb_merge_cand].mv + 1); + mergecandlist[nb_merge_cand].ref_idx[0] = zero_idx < nb_refs ? zero_idx : 0; + mergecandlist[nb_merge_cand].ref_idx[1] = zero_idx < nb_refs ? zero_idx : 0; + + if (merge_idx == nb_merge_cand) + return; + nb_merge_cand++; + zero_idx++; + } +} + +/* + * 8.5.3.1.1 Derivation process of luma Mvs for merge mode + */ +void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW, + int nPbH, int log2_cb_size, int part_idx, + int merge_idx, MvField *mv) +{ + int singleMCLFlag = 0; + int nCS = 1 << log2_cb_size; + LOCAL_ALIGNED(4, MvField, mergecand_list, [MRG_MAX_NUM_CANDS]); + int nPbW2 = nPbW; + int nPbH2 = nPbH; + HEVCLocalContext *lc = s->HEVClc; + + if (s->pps->log2_parallel_merge_level > 2 && nCS == 8) { + singleMCLFlag = 1; + x0 = lc->cu.x; + y0 = lc->cu.y; + nPbW = nCS; + nPbH = nCS; + part_idx = 0; + } + + ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH); + derive_spatial_merge_candidates(s, x0, y0, nPbW, nPbH, log2_cb_size, + singleMCLFlag, part_idx, + merge_idx, mergecand_list); + + if (mergecand_list[merge_idx].pred_flag == PF_BI && + (nPbW2 + nPbH2) == 12) { + mergecand_list[merge_idx].pred_flag = PF_L0; + } + + *mv = mergecand_list[merge_idx]; +} + +static av_always_inline void dist_scale(HEVCContext *s, Mv *mv, + int min_pu_width, int x, int y, + int elist, int ref_idx_curr, int ref_idx) +{ + RefPicList *refPicList = s->ref->refPicList; + MvField *tab_mvf = s->ref->tab_mvf; + int ref_pic_elist = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]]; + int ref_pic_curr = refPicList[ref_idx_curr].list[ref_idx]; + + if (ref_pic_elist != ref_pic_curr) { + int poc_diff = s->poc - ref_pic_elist; + if (!poc_diff) + poc_diff = 1; + mv_scale(mv, mv, poc_diff, s->poc - ref_pic_curr); + } +} + +static int mv_mp_mode_mx(HEVCContext *s, int x, int y, int pred_flag_index, + Mv *mv, int ref_idx_curr, int ref_idx) +{ + MvField *tab_mvf = s->ref->tab_mvf; + int min_pu_width = s->sps->min_pu_width; + + RefPicList *refPicList = s->ref->refPicList; + + if (((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) && + refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) { + *mv = TAB_MVF(x, y).mv[pred_flag_index]; + return 1; + } + return 0; +} + +static int mv_mp_mode_mx_lt(HEVCContext *s, int x, int y, int pred_flag_index, + Mv *mv, int ref_idx_curr, int ref_idx) +{ + MvField *tab_mvf = s->ref->tab_mvf; + int min_pu_width = s->sps->min_pu_width; + + RefPicList *refPicList = s->ref->refPicList; + + if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) { + int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx]; + + int colIsLongTerm = + refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])]; + + if (colIsLongTerm == currIsLongTerm) { + *mv = TAB_MVF(x, y).mv[pred_flag_index]; + if (!currIsLongTerm) + dist_scale(s, mv, min_pu_width, x, y, + pred_flag_index, ref_idx_curr, ref_idx); + return 1; + } + } + return 0; +} + +#define MP_MX(v, pred, mx) \ + mv_mp_mode_mx(s, \ + (x ## v) >> s->sps->log2_min_pu_size, \ + (y ## v) >> s->sps->log2_min_pu_size, \ + pred, &mx, ref_idx_curr, ref_idx) + +#define MP_MX_LT(v, pred, mx) \ + mv_mp_mode_mx_lt(s, \ + (x ## v) >> s->sps->log2_min_pu_size, \ + (y ## v) >> s->sps->log2_min_pu_size, \ + pred, &mx, ref_idx_curr, ref_idx) + +void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW, + int nPbH, int log2_cb_size, int part_idx, + int merge_idx, MvField *mv, + int mvp_lx_flag, int LX) +{ + HEVCLocalContext *lc = s->HEVClc; + MvField *tab_mvf = s->ref->tab_mvf; + int isScaledFlag_L0 = 0; + int availableFlagLXA0 = 1; + int availableFlagLXB0 = 1; + int numMVPCandLX = 0; + int min_pu_width = s->sps->min_pu_width; + + int xA0, yA0; + int is_available_a0; + int xA1, yA1; + int is_available_a1; + int xB0, yB0; + int is_available_b0; + int xB1, yB1; + int is_available_b1; + int xB2, yB2; + int is_available_b2; + + Mv mvpcand_list[2] = { { 0 } }; + Mv mxA; + Mv mxB; + int ref_idx_curr; + int ref_idx = 0; + int pred_flag_index_l0; + int pred_flag_index_l1; + + const int cand_bottom_left = lc->na.cand_bottom_left; + const int cand_left = lc->na.cand_left; + const int cand_up_left = lc->na.cand_up_left; + const int cand_up = lc->na.cand_up; + const int cand_up_right = lc->na.cand_up_right_sap; + ref_idx_curr = LX; + ref_idx = mv->ref_idx[LX]; + pred_flag_index_l0 = LX; + pred_flag_index_l1 = !LX; + + // left bottom spatial candidate + xA0 = x0 - 1; + yA0 = y0 + nPbH; + + is_available_a0 = AVAILABLE(cand_bottom_left, A0) && + yA0 < s->sps->height && + PRED_BLOCK_AVAILABLE(A0); + + //left spatial merge candidate + xA1 = x0 - 1; + yA1 = y0 + nPbH - 1; + + is_available_a1 = AVAILABLE(cand_left, A1); + if (is_available_a0 || is_available_a1) + isScaledFlag_L0 = 1; + + if (is_available_a0) { + if (MP_MX(A0, pred_flag_index_l0, mxA)) { + goto b_candidates; + } + if (MP_MX(A0, pred_flag_index_l1, mxA)) { + goto b_candidates; + } + } + + if (is_available_a1) { + if (MP_MX(A1, pred_flag_index_l0, mxA)) { + goto b_candidates; + } + if (MP_MX(A1, pred_flag_index_l1, mxA)) { + goto b_candidates; + } + } + + if (is_available_a0) { + if (MP_MX_LT(A0, pred_flag_index_l0, mxA)) { + goto b_candidates; + } + if (MP_MX_LT(A0, pred_flag_index_l1, mxA)) { + goto b_candidates; + } + } + + if (is_available_a1) { + if (MP_MX_LT(A1, pred_flag_index_l0, mxA)) { + goto b_candidates; + } + if (MP_MX_LT(A1, pred_flag_index_l1, mxA)) { + goto b_candidates; + } + } + availableFlagLXA0 = 0; + +b_candidates: + // B candidates + // above right spatial merge candidate + xB0 = x0 + nPbW; + yB0 = y0 - 1; + + is_available_b0 = AVAILABLE(cand_up_right, B0) && + xB0 < s->sps->width && + PRED_BLOCK_AVAILABLE(B0); + + // above spatial merge candidate + xB1 = x0 + nPbW - 1; + yB1 = y0 - 1; + is_available_b1 = AVAILABLE(cand_up, B1); + + // above left spatial merge candidate + xB2 = x0 - 1; + yB2 = y0 - 1; + is_available_b2 = AVAILABLE(cand_up_left, B2); + + // above right spatial merge candidate + if (is_available_b0) { + if (MP_MX(B0, pred_flag_index_l0, mxB)) { + goto scalef; + } + if (MP_MX(B0, pred_flag_index_l1, mxB)) { + goto scalef; + } + } + + // above spatial merge candidate + if (is_available_b1) { + if (MP_MX(B1, pred_flag_index_l0, mxB)) { + goto scalef; + } + if (MP_MX(B1, pred_flag_index_l1, mxB)) { + goto scalef; + } + } + + // above left spatial merge candidate + if (is_available_b2) { + if (MP_MX(B2, pred_flag_index_l0, mxB)) { + goto scalef; + } + if (MP_MX(B2, pred_flag_index_l1, mxB)) { + goto scalef; + } + } + availableFlagLXB0 = 0; + +scalef: + if (!isScaledFlag_L0) { + if (availableFlagLXB0) { + availableFlagLXA0 = 1; + mxA = mxB; + } + availableFlagLXB0 = 0; + + // XB0 and L1 + if (is_available_b0) { + availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l0, mxB); + if (!availableFlagLXB0) + availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l1, mxB); + } + + if (is_available_b1 && !availableFlagLXB0) { + availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l0, mxB); + if (!availableFlagLXB0) + availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l1, mxB); + } + + if (is_available_b2 && !availableFlagLXB0) { + availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l0, mxB); + if (!availableFlagLXB0) + availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l1, mxB); + } + } + + if (availableFlagLXA0) + mvpcand_list[numMVPCandLX++] = mxA; + + if (availableFlagLXB0 && (!availableFlagLXA0 || mxA.x != mxB.x || mxA.y != mxB.y)) + mvpcand_list[numMVPCandLX++] = mxB; + + //temporal motion vector prediction candidate + if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag && + mvp_lx_flag == numMVPCandLX) { + Mv mv_col; + int available_col = temporal_luma_motion_vector(s, x0, y0, nPbW, + nPbH, ref_idx, + &mv_col, LX); + if (available_col) + mvpcand_list[numMVPCandLX++] = mv_col; + } + + mv->mv[LX] = mvpcand_list[mvp_lx_flag]; +} +#endif diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c new file mode 100644 index 0000000..834b93b --- /dev/null +++ b/libavcodec/hevc_parser.c @@ -0,0 +1,350 @@ +/* + * HEVC Annex B format parser + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" + +#include "parser.h" +#include "hevc.h" +#include "golomb.h" + +#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes + +typedef struct HEVCParseContext { + HEVCContext h; + ParseContext pc; +} HEVCParseContext; + +/** + * Find the end of the current frame in the bitstream. + * @return the position of the first byte of the next frame, or END_NOT_FOUND + */ +static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, + int buf_size) +{ + int i; + ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc; + + for (i = 0; i < buf_size; i++) { + int nut; + + pc->state64 = (pc->state64 << 8) | buf[i]; + + if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE) + continue; + + nut = (pc->state64 >> 2 * 8 + 1) & 0x3F; + // Beginning of access unit + if ((nut >= NAL_VPS && nut <= NAL_AUD) || nut == NAL_SEI_PREFIX || + (nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) { + if (pc->frame_start_found) { + pc->frame_start_found = 0; + return i - 5; + } + } else if (nut <= NAL_RASL_R || + (nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT)) { + int first_slice_segment_in_pic_flag = buf[i] >> 7; + if (first_slice_segment_in_pic_flag) { + if (!pc->frame_start_found) { + pc->frame_start_found = 1; + } else { // First slice of next frame found + pc->frame_start_found = 0; + return i - 5; + } + } + } + } + + return END_NOT_FOUND; +} + +/** + * Parse NAL units of found picture and decode some basic information. + * + * @param s parser context. + * @param avctx codec context. + * @param buf buffer with field/frame data. + * @param buf_size size of the buffer. + */ +static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h; + GetBitContext *gb = &h->HEVClc->gb; + SliceHeader *sh = &h->sh; + const uint8_t *buf_end = buf + buf_size; + int state = -1, i; + HEVCNAL *nal; + + /* set some sane default values */ + s->pict_type = AV_PICTURE_TYPE_I; + s->key_frame = 0; + s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + h->avctx = avctx; + + if (!buf_size) + return 0; + + if (h->nals_allocated < 1) { + HEVCNAL *tmp = av_realloc_array(h->nals, 1, sizeof(*tmp)); + if (!tmp) + return AVERROR(ENOMEM); + h->nals = tmp; + memset(h->nals, 0, sizeof(*tmp)); + h->nals_allocated = 1; + } + + nal = &h->nals[0]; + + for (;;) { + int src_length, consumed; + buf = avpriv_find_start_code(buf, buf_end, &state); + if (--buf + 2 >= buf_end) + break; + src_length = buf_end - buf; + + h->nal_unit_type = (*buf >> 1) & 0x3f; + h->temporal_id = (*(buf + 1) & 0x07) - 1; + if (h->nal_unit_type <= NAL_CRA_NUT) { + // Do not walk the whole buffer just to decode slice segment header + if (src_length > 20) + src_length = 20; + } + + consumed = ff_hevc_extract_rbsp(h, buf, src_length, nal); + if (consumed < 0) + return consumed; + + init_get_bits8(gb, nal->data + 2, nal->size); + switch (h->nal_unit_type) { + case NAL_VPS: + ff_hevc_decode_nal_vps(h); + break; + case NAL_SPS: + ff_hevc_decode_nal_sps(h); + break; + case NAL_PPS: + ff_hevc_decode_nal_pps(h); + break; + case NAL_SEI_PREFIX: + case NAL_SEI_SUFFIX: + ff_hevc_decode_nal_sei(h); + break; + case NAL_TRAIL_N: + case NAL_TRAIL_R: + case NAL_TSA_N: + case NAL_TSA_R: + case NAL_STSA_N: + case NAL_STSA_R: + case NAL_RADL_N: + case NAL_RADL_R: + case NAL_RASL_N: + case NAL_RASL_R: + case NAL_BLA_W_LP: + case NAL_BLA_W_RADL: + case NAL_BLA_N_LP: + case NAL_IDR_W_RADL: + case NAL_IDR_N_LP: + case NAL_CRA_NUT: + sh->first_slice_in_pic_flag = get_bits1(gb); + s->picture_structure = h->picture_struct; + s->field_order = h->picture_struct; + + if (IS_IRAP(h)) { + s->key_frame = 1; + sh->no_output_of_prior_pics_flag = get_bits1(gb); + } + + sh->pps_id = get_ue_golomb(gb); + if (sh->pps_id >= MAX_PPS_COUNT || !h->pps_list[sh->pps_id]) { + av_log(h->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id); + return AVERROR_INVALIDDATA; + } + h->pps = (HEVCPPS*)h->pps_list[sh->pps_id]->data; + + if (h->pps->sps_id >= MAX_SPS_COUNT || !h->sps_list[h->pps->sps_id]) { + av_log(h->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", h->pps->sps_id); + return AVERROR_INVALIDDATA; + } + if (h->sps != (HEVCSPS*)h->sps_list[h->pps->sps_id]->data) { + h->sps = (HEVCSPS*)h->sps_list[h->pps->sps_id]->data; + h->vps = (HEVCVPS*)h->vps_list[h->sps->vps_id]->data; + } + + if (!sh->first_slice_in_pic_flag) { + int slice_address_length; + + if (h->pps->dependent_slice_segments_enabled_flag) + sh->dependent_slice_segment_flag = get_bits1(gb); + else + sh->dependent_slice_segment_flag = 0; + + slice_address_length = av_ceil_log2_c(h->sps->ctb_width * + h->sps->ctb_height); + sh->slice_segment_addr = get_bits(gb, slice_address_length); + if (sh->slice_segment_addr >= h->sps->ctb_width * h->sps->ctb_height) { + av_log(h->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n", + sh->slice_segment_addr); + return AVERROR_INVALIDDATA; + } + } else + sh->dependent_slice_segment_flag = 0; + + if (sh->dependent_slice_segment_flag) + break; + + for (i = 0; i < h->pps->num_extra_slice_header_bits; i++) + skip_bits(gb, 1); // slice_reserved_undetermined_flag[] + + sh->slice_type = get_ue_golomb(gb); + if (!(sh->slice_type == I_SLICE || sh->slice_type == P_SLICE || + sh->slice_type == B_SLICE)) { + av_log(h->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n", + sh->slice_type); + return AVERROR_INVALIDDATA; + } + s->pict_type = sh->slice_type == B_SLICE ? AV_PICTURE_TYPE_B : + sh->slice_type == P_SLICE ? AV_PICTURE_TYPE_P : + AV_PICTURE_TYPE_I; + + if (h->pps->output_flag_present_flag) + sh->pic_output_flag = get_bits1(gb); + + if (h->sps->separate_colour_plane_flag) + sh->colour_plane_id = get_bits(gb, 2); + + if (!IS_IDR(h)) { + sh->pic_order_cnt_lsb = get_bits(gb, h->sps->log2_max_poc_lsb); + s->output_picture_number = h->poc = ff_hevc_compute_poc(h, sh->pic_order_cnt_lsb); + } else + s->output_picture_number = h->poc = 0; + + if (h->temporal_id == 0 && + h->nal_unit_type != NAL_TRAIL_N && + h->nal_unit_type != NAL_TSA_N && + h->nal_unit_type != NAL_STSA_N && + h->nal_unit_type != NAL_RADL_N && + h->nal_unit_type != NAL_RASL_N && + h->nal_unit_type != NAL_RADL_R && + h->nal_unit_type != NAL_RASL_R) + h->pocTid0 = h->poc; + + return 0; /* no need to evaluate the rest */ + } + buf += consumed; + } + /* didn't find a picture! */ + av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n"); + return -1; +} + +static int hevc_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + int next; + ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = hevc_find_frame_end(s, buf, buf_size); + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + parse_nal_units(s, avctx, buf, buf_size); + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +// Split after the parameter sets at the beginning of the stream if they exist. +static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) +{ + int i; + uint32_t state = -1; + int has_ps = 0; + + for (i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (((state >> 8) & 0xFFFFFF) == START_CODE) { + int nut = (state >> 1) & 0x3F; + if (nut >= NAL_VPS && nut <= NAL_PPS) + has_ps = 1; + else if (has_ps) + return i - 3; + else // no parameter set at the beginning of the stream + return 0; + } + } + return 0; +} + +static int hevc_init(AVCodecParserContext *s) +{ + HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h; + h->HEVClc = av_mallocz(sizeof(HEVCLocalContext)); + h->skipped_bytes_pos_size = INT_MAX; + + return 0; +} + +static void hevc_close(AVCodecParserContext *s) +{ + int i; + HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h; + ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc; + + av_freep(&h->skipped_bytes_pos); + av_freep(&h->HEVClc); + av_freep(&pc->buffer); + + for (i = 0; i < FF_ARRAY_ELEMS(h->vps_list); i++) + av_buffer_unref(&h->vps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h->sps_list); i++) + av_buffer_unref(&h->sps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h->pps_list); i++) + av_buffer_unref(&h->pps_list[i]); + + av_buffer_unref(&h->current_sps); + h->sps = NULL; + + for (i = 0; i < h->nals_allocated; i++) + av_freep(&h->nals[i].rbsp_buffer); + av_freep(&h->nals); + h->nals_allocated = 0; +} + +AVCodecParser ff_hevc_parser = { + .codec_ids = { AV_CODEC_ID_HEVC }, + .priv_data_size = sizeof(HEVCParseContext), + .parser_init = hevc_init, + .parser_parse = hevc_parse, + .parser_close = hevc_close, + .split = hevc_split, +}; diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c new file mode 100644 index 0000000..f1defce --- /dev/null +++ b/libavcodec/hevc_ps.c @@ -0,0 +1,1701 @@ +/* + * HEVC Parameter Set decoding + * + * Copyright (C) 2012 - 2103 Guillaume Martres + * Copyright (C) 2012 - 2103 Mickael Raulet + * Copyright (C) 2012 - 2013 Gildas Cocherel + * Copyright (C) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "golomb.h" +#include "hevc.h" + +static const uint8_t default_scaling_list_intra[] = { + 16, 16, 16, 16, 17, 18, 21, 24, + 16, 16, 16, 16, 17, 19, 22, 25, + 16, 16, 17, 18, 20, 22, 25, 29, + 16, 16, 18, 21, 24, 27, 31, 36, + 17, 17, 20, 24, 30, 35, 41, 47, + 18, 19, 22, 27, 35, 44, 54, 65, + 21, 22, 25, 31, 41, 54, 70, 88, + 24, 25, 29, 36, 47, 65, 88, 115 +}; + +static const uint8_t default_scaling_list_inter[] = { + 16, 16, 16, 16, 17, 18, 20, 24, + 16, 16, 16, 17, 18, 20, 24, 25, + 16, 16, 17, 18, 20, 24, 25, 28, + 16, 17, 18, 20, 24, 25, 28, 33, + 17, 18, 20, 24, 25, 28, 33, 41, + 18, 20, 24, 25, 28, 33, 41, 54, + 20, 24, 25, 28, 33, 41, 54, 71, + 24, 25, 28, 33, 41, 54, 71, 91 +}; + +#ifndef USE_MSPS +static const AVRational vui_sar[] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps, + const HEVCSPS *sps, int is_slice_header) +{ + HEVCLocalContext *lc = s->HEVClc; + uint8_t rps_predict = 0; + int delta_poc; + int k0 = 0; + int k1 = 0; + int k = 0; + int i; + + GetBitContext *gb = &lc->gb; + + if (rps != sps->st_rps && sps->nb_st_rps) + rps_predict = get_bits1(gb); + + if (rps_predict) { + const ShortTermRPS *rps_ridx; + int delta_rps; + unsigned abs_delta_rps; + uint8_t use_delta_flag = 0; + uint8_t delta_rps_sign; + + if (is_slice_header) { + unsigned int delta_idx = get_ue_golomb_long(gb) + 1; + if (delta_idx > sps->nb_st_rps) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid value of delta_idx in slice header RPS: %d > %d.\n", + delta_idx, sps->nb_st_rps); + return AVERROR_INVALIDDATA; + } + rps_ridx = &sps->st_rps[sps->nb_st_rps - delta_idx]; + } else + rps_ridx = &sps->st_rps[rps - sps->st_rps - 1]; + + delta_rps_sign = get_bits1(gb); + abs_delta_rps = get_ue_golomb_long(gb) + 1; + if (abs_delta_rps < 1 || abs_delta_rps > 32768) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid value of abs_delta_rps: %d\n", + abs_delta_rps); + return AVERROR_INVALIDDATA; + } + delta_rps = (1 - (delta_rps_sign << 1)) * abs_delta_rps; + for (i = 0; i <= rps_ridx->num_delta_pocs; i++) { + int used = rps->used[k] = get_bits1(gb); + + if (!used) + use_delta_flag = get_bits1(gb); + + if (used || use_delta_flag) { + if (i < rps_ridx->num_delta_pocs) + delta_poc = delta_rps + rps_ridx->delta_poc[i]; + else + delta_poc = delta_rps; + rps->delta_poc[k] = delta_poc; + if (delta_poc < 0) + k0++; + else + k1++; + k++; + } + } + + rps->num_delta_pocs = k; + rps->num_negative_pics = k0; + // sort in increasing order (smallest first) + if (rps->num_delta_pocs != 0) { + int used, tmp; + for (i = 1; i < rps->num_delta_pocs; i++) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + for (k = i - 1; k >= 0; k--) { + tmp = rps->delta_poc[k]; + if (delta_poc < tmp) { + rps->delta_poc[k + 1] = tmp; + rps->used[k + 1] = rps->used[k]; + rps->delta_poc[k] = delta_poc; + rps->used[k] = used; + } + } + } + } + if ((rps->num_negative_pics >> 1) != 0) { + int used; + k = rps->num_negative_pics - 1; + // flip the negative values to largest first + for (i = 0; i < rps->num_negative_pics >> 1; i++) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + rps->delta_poc[i] = rps->delta_poc[k]; + rps->used[i] = rps->used[k]; + rps->delta_poc[k] = delta_poc; + rps->used[k] = used; + k--; + } + } + } else { + unsigned int prev, nb_positive_pics; + rps->num_negative_pics = get_ue_golomb_long(gb); + nb_positive_pics = get_ue_golomb_long(gb); + + if (rps->num_negative_pics >= MAX_REFS || + nb_positive_pics >= MAX_REFS) { + av_log(s->avctx, AV_LOG_ERROR, "Too many refs in a short term RPS.\n"); + return AVERROR_INVALIDDATA; + } + + rps->num_delta_pocs = rps->num_negative_pics + nb_positive_pics; + if (rps->num_delta_pocs) { + prev = 0; + for (i = 0; i < rps->num_negative_pics; i++) { + delta_poc = get_ue_golomb_long(gb) + 1; + prev -= delta_poc; + rps->delta_poc[i] = prev; + rps->used[i] = get_bits1(gb); + } + prev = 0; + for (i = 0; i < nb_positive_pics; i++) { + delta_poc = get_ue_golomb_long(gb) + 1; + prev += delta_poc; + rps->delta_poc[rps->num_negative_pics + i] = prev; + rps->used[rps->num_negative_pics + i] = get_bits1(gb); + } + } + } + return 0; +} + +static int decode_profile_tier_level(HEVCContext *s, PTLCommon *ptl) +{ + int i; + HEVCLocalContext *lc = s->HEVClc; + GetBitContext *gb = &lc->gb; + + if (get_bits_left(gb) < 2+1+5 + 32 + 4 + 16 + 16 + 12) + return -1; + + ptl->profile_space = get_bits(gb, 2); + ptl->tier_flag = get_bits1(gb); + ptl->profile_idc = get_bits(gb, 5); + if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN) + av_log(s->avctx, AV_LOG_DEBUG, "Main profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN_10) + av_log(s->avctx, AV_LOG_DEBUG, "Main 10 profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN_STILL_PICTURE) + av_log(s->avctx, AV_LOG_DEBUG, "Main Still Picture profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_REXT) + av_log(s->avctx, AV_LOG_DEBUG, "Range Extension profile bitstream\n"); + else + av_log(s->avctx, AV_LOG_WARNING, "Unknown HEVC profile: %d\n", ptl->profile_idc); + + for (i = 0; i < 32; i++) + ptl->profile_compatibility_flag[i] = get_bits1(gb); + ptl->progressive_source_flag = get_bits1(gb); + ptl->interlaced_source_flag = get_bits1(gb); + ptl->non_packed_constraint_flag = get_bits1(gb); + ptl->frame_only_constraint_flag = get_bits1(gb); + + skip_bits(gb, 16); // XXX_reserved_zero_44bits[0..15] + skip_bits(gb, 16); // XXX_reserved_zero_44bits[16..31] + skip_bits(gb, 12); // XXX_reserved_zero_44bits[32..43] + + return 0; +} + +static int parse_ptl(HEVCContext *s, PTL *ptl, int max_num_sub_layers) +{ + int i; + HEVCLocalContext *lc = s->HEVClc; + GetBitContext *gb = &lc->gb; + if (decode_profile_tier_level(s, &ptl->general_ptl) < 0 || + get_bits_left(gb) < 8 + 8*2) { + av_log(s->avctx, AV_LOG_ERROR, "PTL information too short\n"); + return -1; + } + + ptl->general_ptl.level_idc = get_bits(gb, 8); + + for (i = 0; i < max_num_sub_layers - 1; i++) { + ptl->sub_layer_profile_present_flag[i] = get_bits1(gb); + ptl->sub_layer_level_present_flag[i] = get_bits1(gb); + } + + if (max_num_sub_layers - 1> 0) + for (i = max_num_sub_layers - 1; i < 8; i++) + skip_bits(gb, 2); // reserved_zero_2bits[i] + for (i = 0; i < max_num_sub_layers - 1; i++) { + if (ptl->sub_layer_profile_present_flag[i] && + decode_profile_tier_level(s, &ptl->sub_layer_ptl[i]) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "PTL information for sublayer %i too short\n", i); + return -1; + } + if (ptl->sub_layer_level_present_flag[i]) { + if (get_bits_left(gb) < 8) { + av_log(s->avctx, AV_LOG_ERROR, + "Not enough data for sublayer %i level_idc\n", i); + return -1; + } else + ptl->sub_layer_ptl[i].level_idc = get_bits(gb, 8); + } + } + + return 0; +} + +static void decode_sublayer_hrd(HEVCContext *s, unsigned int nb_cpb, + int subpic_params_present) +{ + GetBitContext *gb = &s->HEVClc->gb; + int i; + + for (i = 0; i < nb_cpb; i++) { + get_ue_golomb_long(gb); // bit_rate_value_minus1 + get_ue_golomb_long(gb); // cpb_size_value_minus1 + + if (subpic_params_present) { + get_ue_golomb_long(gb); // cpb_size_du_value_minus1 + get_ue_golomb_long(gb); // bit_rate_du_value_minus1 + } + skip_bits1(gb); // cbr_flag + } +} + +static int decode_hrd(HEVCContext *s, int common_inf_present, + int max_sublayers) +{ + GetBitContext *gb = &s->HEVClc->gb; + int nal_params_present = 0, vcl_params_present = 0; + int subpic_params_present = 0; + int i; + + if (common_inf_present) { + nal_params_present = get_bits1(gb); + vcl_params_present = get_bits1(gb); + + if (nal_params_present || vcl_params_present) { + subpic_params_present = get_bits1(gb); + + if (subpic_params_present) { + skip_bits(gb, 8); // tick_divisor_minus2 + skip_bits(gb, 5); // du_cpb_removal_delay_increment_length_minus1 + skip_bits(gb, 1); // sub_pic_cpb_params_in_pic_timing_sei_flag + skip_bits(gb, 5); // dpb_output_delay_du_length_minus1 + } + + skip_bits(gb, 4); // bit_rate_scale + skip_bits(gb, 4); // cpb_size_scale + + if (subpic_params_present) + skip_bits(gb, 4); // cpb_size_du_scale + + skip_bits(gb, 5); // initial_cpb_removal_delay_length_minus1 + skip_bits(gb, 5); // au_cpb_removal_delay_length_minus1 + skip_bits(gb, 5); // dpb_output_delay_length_minus1 + } + } + + for (i = 0; i < max_sublayers; i++) { + int low_delay = 0; + unsigned int nb_cpb = 1; + int fixed_rate = get_bits1(gb); + + if (!fixed_rate) + fixed_rate = get_bits1(gb); + + if (fixed_rate) + get_ue_golomb_long(gb); // elemental_duration_in_tc_minus1 + else + low_delay = get_bits1(gb); + + if (!low_delay) { + nb_cpb = get_ue_golomb_long(gb) + 1; + if (nb_cpb < 1 || nb_cpb > 32) { + av_log(s->avctx, AV_LOG_ERROR, "nb_cpb %d invalid\n", nb_cpb); + return AVERROR_INVALIDDATA; + } + } + + if (nal_params_present) + decode_sublayer_hrd(s, nb_cpb, subpic_params_present); + if (vcl_params_present) + decode_sublayer_hrd(s, nb_cpb, subpic_params_present); + } + return 0; +} +#endif /* !USE_MSPS */ + +#ifdef USE_MSPS +static int create_dummy_vps(HEVCContext *s) +{ + int i; + int vps_id = 0; + HEVCVPS *vps; + AVBufferRef *vps_buf = av_buffer_allocz(sizeof(*vps)); + + if (!vps_buf) + return AVERROR(ENOMEM); + vps = (HEVCVPS*)vps_buf->data; + + vps_id = 0; + vps->vps_max_layers = 1; + vps->vps_max_sub_layers = 1; + vps->vps_temporal_id_nesting_flag = 0; + + vps->vps_sub_layer_ordering_info_present_flag = 1; + + i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_sub_layers - 1; + for (; i < vps->vps_max_sub_layers; i++) { + vps->vps_max_dec_pic_buffering[i] = 1; + vps->vps_num_reorder_pics[i] = 0; + vps->vps_max_latency_increase[i] = -1; + } + + vps->vps_max_layer_id = 0; + vps->vps_num_layer_sets = 1; + + vps->vps_timing_info_present_flag = 0; + av_buffer_unref(&s->vps_list[vps_id]); + s->vps_list[vps_id] = vps_buf; + return 0; +} +#else +int ff_hevc_decode_nal_vps(HEVCContext *s) +{ + int i,j; + GetBitContext *gb = &s->HEVClc->gb; + int vps_id = 0; + HEVCVPS *vps; + AVBufferRef *vps_buf = av_buffer_allocz(sizeof(*vps)); + + if (!vps_buf) + return AVERROR(ENOMEM); + vps = (HEVCVPS*)vps_buf->data; + + av_log(s->avctx, AV_LOG_DEBUG, "Decoding VPS\n"); + + vps_id = get_bits(gb, 4); + if (vps_id >= MAX_VPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "VPS id out of range: %d\n", vps_id); + goto err; + } + + if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits + av_log(s->avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n"); + goto err; + } + + vps->vps_max_layers = get_bits(gb, 6) + 1; + vps->vps_max_sub_layers = get_bits(gb, 3) + 1; + vps->vps_temporal_id_nesting_flag = get_bits1(gb); + + if (get_bits(gb, 16) != 0xffff) { // vps_reserved_ffff_16bits + av_log(s->avctx, AV_LOG_ERROR, "vps_reserved_ffff_16bits is not 0xffff\n"); + goto err; + } + + if (vps->vps_max_sub_layers > MAX_SUB_LAYERS) { + av_log(s->avctx, AV_LOG_ERROR, "vps_max_sub_layers out of range: %d\n", + vps->vps_max_sub_layers); + goto err; + } + + if (parse_ptl(s, &vps->ptl, vps->vps_max_sub_layers) < 0) + goto err; + + vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb); + + i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_sub_layers - 1; + for (; i < vps->vps_max_sub_layers; i++) { + vps->vps_max_dec_pic_buffering[i] = get_ue_golomb_long(gb) + 1; + vps->vps_num_reorder_pics[i] = get_ue_golomb_long(gb); + vps->vps_max_latency_increase[i] = get_ue_golomb_long(gb) - 1; + + if (vps->vps_max_dec_pic_buffering[i] > MAX_DPB_SIZE || !vps->vps_max_dec_pic_buffering[i]) { + av_log(s->avctx, AV_LOG_ERROR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n", + vps->vps_max_dec_pic_buffering[i] - 1); + goto err; + } + if (vps->vps_num_reorder_pics[i] > vps->vps_max_dec_pic_buffering[i] - 1) { + av_log(s->avctx, AV_LOG_WARNING, "vps_max_num_reorder_pics out of range: %d\n", + vps->vps_num_reorder_pics[i]); + if (s->avctx->err_recognition & AV_EF_EXPLODE) + goto err; + } + } + + vps->vps_max_layer_id = get_bits(gb, 6); + vps->vps_num_layer_sets = get_ue_golomb_long(gb) + 1; + if ((vps->vps_num_layer_sets - 1LL) * (vps->vps_max_layer_id + 1LL) > get_bits_left(gb)) { + av_log(s->avctx, AV_LOG_ERROR, "too many layer_id_included_flags\n"); + goto err; + } + + for (i = 1; i < vps->vps_num_layer_sets; i++) + for (j = 0; j <= vps->vps_max_layer_id; j++) + skip_bits(gb, 1); // layer_id_included_flag[i][j] + + vps->vps_timing_info_present_flag = get_bits1(gb); + if (vps->vps_timing_info_present_flag) { + vps->vps_num_units_in_tick = get_bits_long(gb, 32); + vps->vps_time_scale = get_bits_long(gb, 32); + vps->vps_poc_proportional_to_timing_flag = get_bits1(gb); + if (vps->vps_poc_proportional_to_timing_flag) + vps->vps_num_ticks_poc_diff_one = get_ue_golomb_long(gb) + 1; + vps->vps_num_hrd_parameters = get_ue_golomb_long(gb); + for (i = 0; i < vps->vps_num_hrd_parameters; i++) { + int common_inf_present = 1; + + get_ue_golomb_long(gb); // hrd_layer_set_idx + if (i) + common_inf_present = get_bits1(gb); + decode_hrd(s, common_inf_present, vps->vps_max_sub_layers); + } + } + get_bits1(gb); /* vps_extension_flag */ + + if (get_bits_left(gb) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Overread VPS by %d bits\n", -get_bits_left(gb)); + goto err; + } + + av_buffer_unref(&s->vps_list[vps_id]); + s->vps_list[vps_id] = vps_buf; + return 0; + +err: + av_buffer_unref(&vps_buf); + return AVERROR_INVALIDDATA; +} +#endif + +#ifndef USE_MSPS +static void decode_vui(HEVCContext *s, HEVCSPS *sps) +{ + VUI *vui = &sps->vui; + GetBitContext *gb = &s->HEVClc->gb; + GetBitContext backup; + int sar_present, alt = 0; + + av_log(s->avctx, AV_LOG_DEBUG, "Decoding VUI\n"); + + sar_present = get_bits1(gb); + if (sar_present) { + uint8_t sar_idx = get_bits(gb, 8); + if (sar_idx < FF_ARRAY_ELEMS(vui_sar)) + vui->sar = vui_sar[sar_idx]; + else if (sar_idx == 255) { + vui->sar.num = get_bits(gb, 16); + vui->sar.den = get_bits(gb, 16); + } else + av_log(s->avctx, AV_LOG_WARNING, + "Unknown SAR index: %u.\n", sar_idx); + } + + vui->overscan_info_present_flag = get_bits1(gb); + if (vui->overscan_info_present_flag) + vui->overscan_appropriate_flag = get_bits1(gb); + + vui->video_signal_type_present_flag = get_bits1(gb); + if (vui->video_signal_type_present_flag) { + vui->video_format = get_bits(gb, 3); + vui->video_full_range_flag = get_bits1(gb); + vui->colour_description_present_flag = get_bits1(gb); + if (vui->video_full_range_flag && sps->pix_fmt == AV_PIX_FMT_YUV420P) + sps->pix_fmt = AV_PIX_FMT_YUVJ420P; + if (vui->colour_description_present_flag) { + vui->colour_primaries = get_bits(gb, 8); + vui->transfer_characteristic = get_bits(gb, 8); + vui->matrix_coeffs = get_bits(gb, 8); + + // Set invalid values to "unspecified" + if (vui->colour_primaries >= AVCOL_PRI_NB) + vui->colour_primaries = AVCOL_PRI_UNSPECIFIED; + if (vui->transfer_characteristic >= AVCOL_TRC_NB) + vui->transfer_characteristic = AVCOL_TRC_UNSPECIFIED; + if (vui->matrix_coeffs >= AVCOL_SPC_NB) + vui->matrix_coeffs = AVCOL_SPC_UNSPECIFIED; + } + } + + vui->chroma_loc_info_present_flag = get_bits1(gb); + if (vui->chroma_loc_info_present_flag) { + vui->chroma_sample_loc_type_top_field = get_ue_golomb_long(gb); + vui->chroma_sample_loc_type_bottom_field = get_ue_golomb_long(gb); + } + + vui->neutra_chroma_indication_flag = get_bits1(gb); + vui->field_seq_flag = get_bits1(gb); + vui->frame_field_info_present_flag = get_bits1(gb); + + if (get_bits_left(gb) >= 68 && show_bits_long(gb, 21) == 0x100000) { + vui->default_display_window_flag = 0; + av_log(s->avctx, AV_LOG_WARNING, "Invalid default display window\n"); + } else + vui->default_display_window_flag = get_bits1(gb); + // Backup context in case an alternate header is detected + memcpy(&backup, gb, sizeof(backup)); + + if (vui->default_display_window_flag) { + //TODO: * 2 is only valid for 420 + vui->def_disp_win.left_offset = get_ue_golomb_long(gb) * 2; + vui->def_disp_win.right_offset = get_ue_golomb_long(gb) * 2; + vui->def_disp_win.top_offset = get_ue_golomb_long(gb) * 2; + vui->def_disp_win.bottom_offset = get_ue_golomb_long(gb) * 2; + + if (s->apply_defdispwin && + s->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) { + av_log(s->avctx, AV_LOG_DEBUG, + "discarding vui default display window, " + "original values are l:%u r:%u t:%u b:%u\n", + vui->def_disp_win.left_offset, + vui->def_disp_win.right_offset, + vui->def_disp_win.top_offset, + vui->def_disp_win.bottom_offset); + + vui->def_disp_win.left_offset = + vui->def_disp_win.right_offset = + vui->def_disp_win.top_offset = + vui->def_disp_win.bottom_offset = 0; + } + } + + vui->vui_timing_info_present_flag = get_bits1(gb); + + if (vui->vui_timing_info_present_flag) { + if( get_bits_left(gb) < 66) { + // The alternate syntax seem to have timing info located + // at where def_disp_win is normally located + av_log(s->avctx, AV_LOG_WARNING, + "Strange VUI timing information, retrying...\n"); + vui->default_display_window_flag = 0; + memset(&vui->def_disp_win, 0, sizeof(vui->def_disp_win)); + memcpy(gb, &backup, sizeof(backup)); + alt = 1; + } + vui->vui_num_units_in_tick = get_bits_long(gb, 32); + vui->vui_time_scale = get_bits_long(gb, 32); + if (alt) { + av_log(s->avctx, AV_LOG_INFO, "Retry got %i/%i fps\n", + vui->vui_time_scale, vui->vui_num_units_in_tick); + } + vui->vui_poc_proportional_to_timing_flag = get_bits1(gb); + if (vui->vui_poc_proportional_to_timing_flag) + vui->vui_num_ticks_poc_diff_one_minus1 = get_ue_golomb_long(gb); + vui->vui_hrd_parameters_present_flag = get_bits1(gb); + if (vui->vui_hrd_parameters_present_flag) + decode_hrd(s, 1, sps->max_sub_layers); + } + + vui->bitstream_restriction_flag = get_bits1(gb); + if (vui->bitstream_restriction_flag) { + vui->tiles_fixed_structure_flag = get_bits1(gb); + vui->motion_vectors_over_pic_boundaries_flag = get_bits1(gb); + vui->restricted_ref_pic_lists_flag = get_bits1(gb); + vui->min_spatial_segmentation_idc = get_ue_golomb_long(gb); + vui->max_bytes_per_pic_denom = get_ue_golomb_long(gb); + vui->max_bits_per_min_cu_denom = get_ue_golomb_long(gb); + vui->log2_max_mv_length_horizontal = get_ue_golomb_long(gb); + vui->log2_max_mv_length_vertical = get_ue_golomb_long(gb); + } +} +#endif /* !USE_MSPS */ + +static void set_default_scaling_list_data(ScalingList *sl) +{ + int matrixId; + + for (matrixId = 0; matrixId < 6; matrixId++) { + // 4x4 default is 16 + memset(sl->sl[0][matrixId], 16, 16); + sl->sl_dc[0][matrixId] = 16; // default for 16x16 + sl->sl_dc[1][matrixId] = 16; // default for 32x32 + } + memcpy(sl->sl[1][0], default_scaling_list_intra, 64); + memcpy(sl->sl[1][1], default_scaling_list_intra, 64); + memcpy(sl->sl[1][2], default_scaling_list_intra, 64); + memcpy(sl->sl[1][3], default_scaling_list_inter, 64); + memcpy(sl->sl[1][4], default_scaling_list_inter, 64); + memcpy(sl->sl[1][5], default_scaling_list_inter, 64); + memcpy(sl->sl[2][0], default_scaling_list_intra, 64); + memcpy(sl->sl[2][1], default_scaling_list_intra, 64); + memcpy(sl->sl[2][2], default_scaling_list_intra, 64); + memcpy(sl->sl[2][3], default_scaling_list_inter, 64); + memcpy(sl->sl[2][4], default_scaling_list_inter, 64); + memcpy(sl->sl[2][5], default_scaling_list_inter, 64); + memcpy(sl->sl[3][0], default_scaling_list_intra, 64); + memcpy(sl->sl[3][1], default_scaling_list_intra, 64); + memcpy(sl->sl[3][2], default_scaling_list_intra, 64); + memcpy(sl->sl[3][3], default_scaling_list_inter, 64); + memcpy(sl->sl[3][4], default_scaling_list_inter, 64); + memcpy(sl->sl[3][5], default_scaling_list_inter, 64); +} + +static int scaling_list_data(HEVCContext *s, ScalingList *sl, HEVCSPS *sps) +{ + GetBitContext *gb = &s->HEVClc->gb; + uint8_t scaling_list_pred_mode_flag; + int32_t scaling_list_dc_coef[2][6]; + int size_id, matrix_id, pos; + int i; + + for (size_id = 0; size_id < 4; size_id++) + for (matrix_id = 0; matrix_id < 6; matrix_id += ((size_id == 3) ? 3 : 1)) { + scaling_list_pred_mode_flag = get_bits1(gb); + if (!scaling_list_pred_mode_flag) { + unsigned int delta = get_ue_golomb_long(gb); + /* Only need to handle non-zero delta. Zero means default, + * which should already be in the arrays. */ + if (delta) { + // Copy from previous array. + if (matrix_id < delta) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid delta in scaling list data: %d.\n", delta); + return AVERROR_INVALIDDATA; + } + + memcpy(sl->sl[size_id][matrix_id], + sl->sl[size_id][matrix_id - delta], + size_id > 0 ? 64 : 16); + if (size_id > 1) + sl->sl_dc[size_id - 2][matrix_id] = sl->sl_dc[size_id - 2][matrix_id - delta]; + } + } else { + int next_coef, coef_num; + int32_t scaling_list_delta_coef; + + next_coef = 8; + coef_num = FFMIN(64, 1 << (4 + (size_id << 1))); + if (size_id > 1) { + scaling_list_dc_coef[size_id - 2][matrix_id] = get_se_golomb(gb) + 8; + next_coef = scaling_list_dc_coef[size_id - 2][matrix_id]; + sl->sl_dc[size_id - 2][matrix_id] = next_coef; + } + for (i = 0; i < coef_num; i++) { + if (size_id == 0) + pos = 4 * ff_hevc_diag_scan4x4_y[i] + + ff_hevc_diag_scan4x4_x[i]; + else + pos = 8 * ff_hevc_diag_scan8x8_y[i] + + ff_hevc_diag_scan8x8_x[i]; + + scaling_list_delta_coef = get_se_golomb(gb); + next_coef = (next_coef + scaling_list_delta_coef + 256) % 256; + sl->sl[size_id][matrix_id][pos] = next_coef; + } + } + } + + if (sps->chroma_format_idc == 3) { + for (i = 0; i < 64; i++) { + sl->sl[3][1][i] = sl->sl[2][1][i]; + sl->sl[3][2][i] = sl->sl[2][2][i]; + sl->sl[3][4][i] = sl->sl[2][4][i]; + sl->sl[3][5][i] = sl->sl[2][5][i]; + } + sl->sl_dc[1][1] = sl->sl_dc[0][1]; + sl->sl_dc[1][2] = sl->sl_dc[0][2]; + sl->sl_dc[1][4] = sl->sl_dc[0][4]; + sl->sl_dc[1][5] = sl->sl_dc[0][5]; + } + + + return 0; +} + +int ff_hevc_decode_nal_sps(HEVCContext *s) +{ + const AVPixFmtDescriptor *desc; + GetBitContext *gb = &s->HEVClc->gb; + int ret = 0; + unsigned int sps_id = 0; + int log2_diff_max_min_transform_block_size; +#ifndef USE_MSPS + int bit_depth_chroma, start, vui_present, sublayer_ordering_info; +#endif + int i; + + HEVCSPS *sps; + AVBufferRef *sps_buf = av_buffer_allocz(sizeof(*sps)); + + if (!sps_buf) + return AVERROR(ENOMEM); + sps = (HEVCSPS*)sps_buf->data; + + av_log(s->avctx, AV_LOG_DEBUG, "Decoding SPS\n"); + + // Coded parameters +#ifdef USE_MSPS + ret = create_dummy_vps(s); + if (ret < 0) + return ret; + sps->vps_id = 0; + sps->max_sub_layers = 1; + + sps_id = 0; + + sps->chroma_format_idc = get_bits(gb, 8); + if (sps->chroma_format_idc > 3) { + ret = AVERROR_INVALIDDATA; + goto err; + } + sps->separate_colour_plane_flag = 0; + + sps->width = get_bits_long(gb, 32); + sps->height = get_bits_long(gb, 32); + if ((ret = av_image_check_size(sps->width, + sps->height, 0, s->avctx)) < 0) + goto err; + sps->bit_depth = get_bits(gb, 8) + 8; + +#ifdef USE_VAR_BIT_DEPTH + /* Note: in order to simplify the code we always use 16 bit pixfmt */ + switch(sps->chroma_format_idc) { + case 0: + sps->pix_fmt = AV_PIX_FMT_GRAY16; + break; + case 1: + sps->pix_fmt = AV_PIX_FMT_YUV420P16; + break; + case 2: + sps->pix_fmt = AV_PIX_FMT_YUV422P16; + break; + default: + case 3: + sps->pix_fmt = AV_PIX_FMT_YUV444P16; + break; + } + sps->pixel_shift = 1; +#else + if (sps->bit_depth != 8) { + ret = AVERROR_INVALIDDATA; + goto err; + } + + switch(sps->chroma_format_idc) { + case 0: + sps->pix_fmt = AV_PIX_FMT_GRAY8; + break; + case 1: + sps->pix_fmt = AV_PIX_FMT_YUV420P; + break; + case 2: + sps->pix_fmt = AV_PIX_FMT_YUV422P; + break; + default: + case 3: + sps->pix_fmt = AV_PIX_FMT_YUV444P; + break; + } + sps->pixel_shift = 0; +#endif /* !USE_VAR_BIT_DEPTH */ + +#else + sps->vps_id = get_bits(gb, 4); + if (sps->vps_id >= MAX_VPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "VPS id out of range: %d\n", sps->vps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + if (!s->vps_list[sps->vps_id]) { + av_log(s->avctx, AV_LOG_ERROR, "VPS %d does not exist\n", + sps->vps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + + sps->max_sub_layers = get_bits(gb, 3) + 1; + if (sps->max_sub_layers > MAX_SUB_LAYERS) { + av_log(s->avctx, AV_LOG_ERROR, "sps_max_sub_layers out of range: %d\n", + sps->max_sub_layers); + ret = AVERROR_INVALIDDATA; + goto err; + } + + skip_bits1(gb); // temporal_id_nesting_flag + + if (parse_ptl(s, &sps->ptl, sps->max_sub_layers) < 0) + goto err; + + sps_id = get_ue_golomb_long(gb); + if (sps_id >= MAX_SPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", sps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + + sps->chroma_format_idc = get_ue_golomb_long(gb); + if (!(sps->chroma_format_idc == 1 || sps->chroma_format_idc == 2 || sps->chroma_format_idc == 3 || sps->chroma_format_idc == 0)) { + avpriv_report_missing_feature(s->avctx, "chroma_format_idc != {0, 1, 2, 3}\n"); + ret = AVERROR_PATCHWELCOME; + goto err; + } + + if (sps->chroma_format_idc == 3) + sps->separate_colour_plane_flag = get_bits1(gb); + + if (sps->separate_colour_plane_flag) { + sps->chroma_format_idc = 0; + avpriv_report_missing_feature(s->avctx, "separate_colour_plane_flag = 1\n"); + ret = AVERROR_PATCHWELCOME; + goto err; + } + + sps->width = get_ue_golomb_long(gb); + sps->height = get_ue_golomb_long(gb); + if ((ret = av_image_check_size(sps->width, + sps->height, 0, s->avctx)) < 0) + goto err; + + if (get_bits1(gb)) { // pic_conformance_flag + int hshift, vshift; + switch(sps->chroma_format_idc) { + default: + case 0: + case 3: + hshift = vshift = 0; + break; + case 1: + hshift = vshift = 1; + break; + case 2: + hshift = 1; + vshift = 0; + break; + } + sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) << hshift; + sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) << hshift; + sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) << vshift; + sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) << vshift; + + if (s->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) { + av_log(s->avctx, AV_LOG_DEBUG, + "discarding sps conformance window, " + "original values are l:%u r:%u t:%u b:%u\n", + sps->pic_conf_win.left_offset, + sps->pic_conf_win.right_offset, + sps->pic_conf_win.top_offset, + sps->pic_conf_win.bottom_offset); + + sps->pic_conf_win.left_offset = + sps->pic_conf_win.right_offset = + sps->pic_conf_win.top_offset = + sps->pic_conf_win.bottom_offset = 0; + } + sps->output_window = sps->pic_conf_win; + } + + sps->bit_depth = get_ue_golomb_long(gb) + 8; + bit_depth_chroma = get_ue_golomb_long(gb) + 8; + if (bit_depth_chroma != sps->bit_depth && sps->chroma_format_idc != 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Luma bit depth (%d) is different from chroma bit depth (%d), " + "this is unsupported.\n", + sps->bit_depth, bit_depth_chroma); + ret = AVERROR_INVALIDDATA; + goto err; + } + switch (sps->bit_depth) { + case 8: + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P; + break; + case 9: + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P9; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P9; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P9; + break; + case 10: + if (sps->chroma_format_idc == 0) { + if (sps->separate_colour_plane_flag) + goto format_not_supported; + sps->pix_fmt = AV_PIX_FMT_GRAY16; /* XXX: should have gray10 */ + } + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P10; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P10; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P10; + break; + case 12: + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P12; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P12; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P12; + break; + default: + format_not_supported: + av_log(s->avctx, AV_LOG_ERROR, + "4:2:0, 4:2:2, 4:4:4 supports are currently specified for 8, 10 and 12 bits.\n"); + ret = AVERROR_PATCHWELCOME; + goto err; + } + sps->pixel_shift = sps->bit_depth > 8; +#endif /* USE_MSPS */ + + desc = av_pix_fmt_desc_get(sps->pix_fmt); + if (!desc) { + ret = AVERROR(EINVAL); + goto err; + } + + sps->hshift[0] = sps->vshift[0] = 0; + sps->hshift[2] = sps->hshift[1] = desc->log2_chroma_w; + sps->vshift[2] = sps->vshift[1] = desc->log2_chroma_h; + + +#ifdef USE_MSPS + sps->log2_max_poc_lsb = 8; /* not used */ + for (i = 0; i < sps->max_sub_layers; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = 1; + sps->temporal_layer[i].num_reorder_pics = 0; + sps->temporal_layer[i].max_latency_increase = -1; + } + sps->log2_min_cb_size = get_ue_golomb_long(gb) + 3; + /* update the width & heigth to be a multiple of min_cb_size */ + { + int m; + m = (1 << sps->log2_min_cb_size) - 1; + sps->width = (sps->width + m) & ~m; + sps->height = (sps->height + m) & ~m; + } +#else + sps->log2_max_poc_lsb = get_ue_golomb_long(gb) + 4; + if (sps->log2_max_poc_lsb > 16) { + av_log(s->avctx, AV_LOG_ERROR, "log2_max_pic_order_cnt_lsb_minus4 out range: %d\n", + sps->log2_max_poc_lsb - 4); + ret = AVERROR_INVALIDDATA; + goto err; + } + + sublayer_ordering_info = get_bits1(gb); + start = sublayer_ordering_info ? 0 : sps->max_sub_layers - 1; + for (i = start; i < sps->max_sub_layers; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; + sps->temporal_layer[i].num_reorder_pics = get_ue_golomb_long(gb); + sps->temporal_layer[i].max_latency_increase = get_ue_golomb_long(gb) - 1; + if (sps->temporal_layer[i].max_dec_pic_buffering > MAX_DPB_SIZE) { + av_log(s->avctx, AV_LOG_ERROR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n", + sps->temporal_layer[i].max_dec_pic_buffering - 1); + ret = AVERROR_INVALIDDATA; + goto err; + } + if (sps->temporal_layer[i].num_reorder_pics > sps->temporal_layer[i].max_dec_pic_buffering - 1) { + av_log(s->avctx, AV_LOG_WARNING, "sps_max_num_reorder_pics out of range: %d\n", + sps->temporal_layer[i].num_reorder_pics); + if (s->avctx->err_recognition & AV_EF_EXPLODE || + sps->temporal_layer[i].num_reorder_pics > MAX_DPB_SIZE - 1) { + ret = AVERROR_INVALIDDATA; + goto err; + } + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[i].num_reorder_pics + 1; + } + } + + if (!sublayer_ordering_info) { + for (i = 0; i < start; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[start].max_dec_pic_buffering; + sps->temporal_layer[i].num_reorder_pics = sps->temporal_layer[start].num_reorder_pics; + sps->temporal_layer[i].max_latency_increase = sps->temporal_layer[start].max_latency_increase; + } + } + sps->log2_min_cb_size = get_ue_golomb_long(gb) + 3; +#endif + sps->log2_diff_max_min_coding_block_size = get_ue_golomb_long(gb); + sps->log2_min_tb_size = get_ue_golomb_long(gb) + 2; + log2_diff_max_min_transform_block_size = get_ue_golomb_long(gb); + sps->log2_max_trafo_size = log2_diff_max_min_transform_block_size + + sps->log2_min_tb_size; + if (sps->log2_min_tb_size >= sps->log2_min_cb_size) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid value for log2_min_tb_size"); + ret = AVERROR_INVALIDDATA; + goto err; + } +#ifdef USE_MSPS + sps->max_transform_hierarchy_depth_inter = 0; /* not used for intra */ +#else + sps->max_transform_hierarchy_depth_inter = get_ue_golomb_long(gb); +#endif + sps->max_transform_hierarchy_depth_intra = get_ue_golomb_long(gb); + +#ifndef USE_MSPS + sps->scaling_list_enable_flag = get_bits1(gb); + if (sps->scaling_list_enable_flag) { +#ifdef USE_FULL + set_default_scaling_list_data(&sps->scaling_list); + + if (get_bits1(gb)) { + ret = scaling_list_data(s, &sps->scaling_list, sps); + if (ret < 0) + goto err; + } +#else + abort(); +#endif + } + sps->amp_enabled_flag = get_bits1(gb); +#endif + + sps->sao_enabled = get_bits1(gb); + + sps->pcm_enabled_flag = get_bits1(gb); + if (sps->pcm_enabled_flag) { + sps->pcm.bit_depth = get_bits(gb, 4) + 1; + sps->pcm.bit_depth_chroma = get_bits(gb, 4) + 1; + sps->pcm.log2_min_pcm_cb_size = get_ue_golomb_long(gb) + 3; + sps->pcm.log2_max_pcm_cb_size = sps->pcm.log2_min_pcm_cb_size + + get_ue_golomb_long(gb); + if (sps->pcm.bit_depth > sps->bit_depth) { + av_log(s->avctx, AV_LOG_ERROR, + "PCM bit depth (%d) is greater than normal bit depth (%d)\n", + sps->pcm.bit_depth, sps->bit_depth); + ret = AVERROR_INVALIDDATA; + goto err; + } + + sps->pcm.loop_filter_disable_flag = get_bits1(gb); + } + +#ifdef USE_MSPS + sps->nb_st_rps = 0; /* not used for intra */ + sps->long_term_ref_pics_present_flag = 0; /* not used for intra */ + sps->sps_temporal_mvp_enabled_flag = 0; /* not used for intra */ + sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb); + sps->vui.sar = (AVRational){0, 1}; +#else + sps->nb_st_rps = get_ue_golomb_long(gb); + if (sps->nb_st_rps > MAX_SHORT_TERM_RPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "Too many short term RPS: %d.\n", + sps->nb_st_rps); + ret = AVERROR_INVALIDDATA; + goto err; + } + for (i = 0; i < sps->nb_st_rps; i++) { + if ((ret = ff_hevc_decode_short_term_rps(s, &sps->st_rps[i], + sps, 0)) < 0) + goto err; + } + + sps->long_term_ref_pics_present_flag = get_bits1(gb); + if (sps->long_term_ref_pics_present_flag) { + sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb); + for (i = 0; i < sps->num_long_term_ref_pics_sps; i++) { + sps->lt_ref_pic_poc_lsb_sps[i] = get_bits(gb, sps->log2_max_poc_lsb); + sps->used_by_curr_pic_lt_sps_flag[i] = get_bits1(gb); + } + } + + sps->sps_temporal_mvp_enabled_flag = get_bits1(gb); + sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb); + sps->vui.sar = (AVRational){0, 1}; + vui_present = get_bits1(gb); + if (vui_present) + decode_vui(s, sps); +#endif + + if (get_bits1(gb)) { // sps_extension_flag + int sps_extension_flag[1]; + for (i = 0; i < 1; i++) + sps_extension_flag[i] = get_bits1(gb); + skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7); + if (sps_extension_flag[0]) { + int extended_precision_processing_flag; + int high_precision_offsets_enabled_flag; + int cabac_bypass_alignment_enabled_flag; + + sps->transform_skip_rotation_enabled_flag = get_bits1(gb); + sps->transform_skip_context_enabled_flag = get_bits1(gb); + sps->implicit_rdpcm_enabled_flag = get_bits1(gb); + sps->explicit_rdpcm_enabled_flag = get_bits1(gb); + + extended_precision_processing_flag = get_bits1(gb); + if (extended_precision_processing_flag) + av_log(s->avctx, AV_LOG_WARNING, + "extended_precision_processing_flag not yet implemented\n"); + + sps->intra_smoothing_disabled_flag = get_bits1(gb); + high_precision_offsets_enabled_flag = get_bits1(gb); + if (high_precision_offsets_enabled_flag) + av_log(s->avctx, AV_LOG_WARNING, + "high_precision_offsets_enabled_flag not yet implemented\n"); + + sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb); + + cabac_bypass_alignment_enabled_flag = get_bits1(gb); + if (cabac_bypass_alignment_enabled_flag) + av_log(s->avctx, AV_LOG_WARNING, + "cabac_bypass_alignment_enabled_flag not yet implemented\n"); + } + } +#ifdef USE_MSPS + sps->output_width = sps->width; + sps->output_height = sps->height; +#else + if (s->apply_defdispwin) { + sps->output_window.left_offset += sps->vui.def_disp_win.left_offset; + sps->output_window.right_offset += sps->vui.def_disp_win.right_offset; + sps->output_window.top_offset += sps->vui.def_disp_win.top_offset; + sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset; + } + if (sps->output_window.left_offset & (0x1F >> (sps->pixel_shift)) && + !(s->avctx->flags & CODEC_FLAG_UNALIGNED)) { + sps->output_window.left_offset &= ~(0x1F >> (sps->pixel_shift)); + av_log(s->avctx, AV_LOG_WARNING, "Reducing left output window to %d " + "chroma samples to preserve alignment.\n", + sps->output_window.left_offset); + } + sps->output_width = sps->width - + (sps->output_window.left_offset + sps->output_window.right_offset); + sps->output_height = sps->height - + (sps->output_window.top_offset + sps->output_window.bottom_offset); + if (sps->output_width <= 0 || sps->output_height <= 0) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n", + sps->output_width, sps->output_height); + if (s->avctx->err_recognition & AV_EF_EXPLODE) { + ret = AVERROR_INVALIDDATA; + goto err; + } + av_log(s->avctx, AV_LOG_WARNING, + "Displaying the whole video surface.\n"); + sps->pic_conf_win.left_offset = + sps->pic_conf_win.right_offset = + sps->pic_conf_win.top_offset = + sps->pic_conf_win.bottom_offset = 0; + sps->output_width = sps->width; + sps->output_height = sps->height; + } +#endif + + // Inferred parameters + sps->log2_ctb_size = sps->log2_min_cb_size + + sps->log2_diff_max_min_coding_block_size; + sps->log2_min_pu_size = sps->log2_min_cb_size - 1; + + sps->ctb_width = (sps->width + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size; + sps->ctb_height = (sps->height + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size; + sps->ctb_size = sps->ctb_width * sps->ctb_height; + + sps->min_cb_width = sps->width >> sps->log2_min_cb_size; + sps->min_cb_height = sps->height >> sps->log2_min_cb_size; + sps->min_tb_width = sps->width >> sps->log2_min_tb_size; + sps->min_tb_height = sps->height >> sps->log2_min_tb_size; + sps->min_pu_width = sps->width >> sps->log2_min_pu_size; + sps->min_pu_height = sps->height >> sps->log2_min_pu_size; + sps->tb_mask = (1 << (sps->log2_ctb_size - sps->log2_min_tb_size)) - 1; + + sps->qp_bd_offset = 6 * (sps->bit_depth - 8); + + if (sps->width & ((1 << sps->log2_min_cb_size) - 1) || + sps->height & ((1 << sps->log2_min_cb_size) - 1)) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid coded frame dimensions.\n"); + goto err; + } + + if (sps->log2_ctb_size > MAX_LOG2_CTB_SIZE) { + av_log(s->avctx, AV_LOG_ERROR, "CTB size out of range: 2^%d\n", sps->log2_ctb_size); + goto err; + } + if (sps->max_transform_hierarchy_depth_inter > sps->log2_ctb_size - sps->log2_min_tb_size) { + av_log(s->avctx, AV_LOG_ERROR, "max_transform_hierarchy_depth_inter out of range: %d\n", + sps->max_transform_hierarchy_depth_inter); + goto err; + } + if (sps->max_transform_hierarchy_depth_intra > sps->log2_ctb_size - sps->log2_min_tb_size) { + av_log(s->avctx, AV_LOG_ERROR, "max_transform_hierarchy_depth_intra out of range: %d\n", + sps->max_transform_hierarchy_depth_intra); + goto err; + } + if (sps->log2_max_trafo_size > FFMIN(sps->log2_ctb_size, 5)) { + av_log(s->avctx, AV_LOG_ERROR, + "max transform block size out of range: %d\n", + sps->log2_max_trafo_size); + goto err; + } + + if (get_bits_left(gb) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Overread SPS by %d bits\n", -get_bits_left(gb)); + goto err; + } + + if (s->avctx->debug & FF_DEBUG_BITSTREAM) { + av_log(s->avctx, AV_LOG_DEBUG, + "Parsed SPS: id %d; coded wxh: %dx%d; " + "cropped wxh: %dx%d; pix_fmt: %s.\n", + sps_id, sps->width, sps->height, + sps->output_width, sps->output_height, +#ifdef USE_FULL + av_get_pix_fmt_name(sps->pix_fmt) +#else + "?" +#endif + ); + } + + /* check if this is a repeat of an already parsed SPS, then keep the + * original one. + * otherwise drop all PPSes that depend on it */ + if (s->sps_list[sps_id] && + !memcmp(s->sps_list[sps_id]->data, sps_buf->data, sps_buf->size)) { + av_buffer_unref(&sps_buf); + } else { + for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) { + if (s->pps_list[i] && ((HEVCPPS*)s->pps_list[i]->data)->sps_id == sps_id) + av_buffer_unref(&s->pps_list[i]); + } + if (s->sps_list[sps_id] && s->sps == (HEVCSPS*)s->sps_list[sps_id]->data) { + av_buffer_unref(&s->current_sps); + s->current_sps = av_buffer_ref(s->sps_list[sps_id]); + if (!s->current_sps) + s->sps = NULL; + } + av_buffer_unref(&s->sps_list[sps_id]); + s->sps_list[sps_id] = sps_buf; + } + + return 0; + +err: + av_buffer_unref(&sps_buf); + return ret; +} + +static void hevc_pps_free(void *opaque, uint8_t *data) +{ + HEVCPPS *pps = (HEVCPPS*)data; + + av_freep(&pps->column_width); + av_freep(&pps->row_height); + av_freep(&pps->col_bd); + av_freep(&pps->row_bd); + av_freep(&pps->col_idxX); + av_freep(&pps->ctb_addr_rs_to_ts); + av_freep(&pps->ctb_addr_ts_to_rs); + av_freep(&pps->tile_pos_rs); + av_freep(&pps->tile_id); + av_freep(&pps->min_tb_addr_zs_tab); + + av_freep(&pps); +} + +static int pps_range_extensions(HEVCContext *s, HEVCPPS *pps, HEVCSPS *sps) { + GetBitContext *gb = &s->HEVClc->gb; + int i; + + if (pps->transform_skip_enabled_flag) { + pps->log2_max_transform_skip_block_size = get_ue_golomb_long(gb) + 2; + } + pps->cross_component_prediction_enabled_flag = get_bits1(gb); + pps->chroma_qp_offset_list_enabled_flag = get_bits1(gb); + if (pps->chroma_qp_offset_list_enabled_flag) { + pps->diff_cu_chroma_qp_offset_depth = get_ue_golomb_long(gb); + pps->chroma_qp_offset_list_len_minus1 = get_ue_golomb_long(gb); + if (pps->chroma_qp_offset_list_len_minus1 && pps->chroma_qp_offset_list_len_minus1 >= 5) { + av_log(s->avctx, AV_LOG_ERROR, + "chroma_qp_offset_list_len_minus1 shall be in the range [0, 5].\n"); + return AVERROR_INVALIDDATA; + } + for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) { + pps->cb_qp_offset_list[i] = get_se_golomb_long(gb); + if (pps->cb_qp_offset_list[i]) { + av_log(s->avctx, AV_LOG_WARNING, + "cb_qp_offset_list not tested yet.\n"); + } + pps->cr_qp_offset_list[i] = get_se_golomb_long(gb); + if (pps->cr_qp_offset_list[i]) { + av_log(s->avctx, AV_LOG_WARNING, + "cb_qp_offset_list not tested yet.\n"); + } + } + } + pps->log2_sao_offset_scale_luma = get_ue_golomb_long(gb); + pps->log2_sao_offset_scale_chroma = get_ue_golomb_long(gb); + + return(0); +} + +int ff_hevc_decode_nal_pps(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + HEVCSPS *sps = NULL; + int pic_area_in_ctbs; + int log2_diff_ctb_min_tb_size; + int i, j, x, y, ctb_addr_rs, tile_id; + int ret = 0; + unsigned int pps_id = 0; + + AVBufferRef *pps_buf; + HEVCPPS *pps = av_mallocz(sizeof(*pps)); + + if (!pps) + return AVERROR(ENOMEM); + + pps_buf = av_buffer_create((uint8_t *)pps, sizeof(*pps), + hevc_pps_free, NULL, 0); + if (!pps_buf) { + av_freep(&pps); + return AVERROR(ENOMEM); + } + + av_log(s->avctx, AV_LOG_DEBUG, "Decoding PPS\n"); + + // Default values + pps->loop_filter_across_tiles_enabled_flag = 1; + pps->num_tile_columns = 1; + pps->num_tile_rows = 1; + pps->uniform_spacing_flag = 1; + pps->disable_dbf = 0; + pps->beta_offset = 0; + pps->tc_offset = 0; + pps->log2_max_transform_skip_block_size = 2; + + // Coded parameters + pps_id = get_ue_golomb_long(gb); + if (pps_id >= MAX_PPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + pps->sps_id = get_ue_golomb_long(gb); + if (pps->sps_id >= MAX_SPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", pps->sps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + if (!s->sps_list[pps->sps_id]) { + av_log(s->avctx, AV_LOG_ERROR, "SPS %u does not exist.\n", pps->sps_id); + ret = AVERROR_INVALIDDATA; + goto err; + } + sps = (HEVCSPS *)s->sps_list[pps->sps_id]->data; + + pps->dependent_slice_segments_enabled_flag = get_bits1(gb); + pps->output_flag_present_flag = get_bits1(gb); + pps->num_extra_slice_header_bits = get_bits(gb, 3); + + pps->sign_data_hiding_flag = get_bits1(gb); + + pps->cabac_init_present_flag = get_bits1(gb); + + pps->num_ref_idx_l0_default_active = get_ue_golomb_long(gb) + 1; + pps->num_ref_idx_l1_default_active = get_ue_golomb_long(gb) + 1; + + pps->pic_init_qp_minus26 = get_se_golomb(gb); + + pps->constrained_intra_pred_flag = get_bits1(gb); + pps->transform_skip_enabled_flag = get_bits1(gb); + + pps->cu_qp_delta_enabled_flag = get_bits1(gb); + pps->diff_cu_qp_delta_depth = 0; + if (pps->cu_qp_delta_enabled_flag) + pps->diff_cu_qp_delta_depth = get_ue_golomb_long(gb); + + pps->cb_qp_offset = get_se_golomb(gb); + if (pps->cb_qp_offset < -12 || pps->cb_qp_offset > 12) { + av_log(s->avctx, AV_LOG_ERROR, "pps_cb_qp_offset out of range: %d\n", + pps->cb_qp_offset); + ret = AVERROR_INVALIDDATA; + goto err; + } + pps->cr_qp_offset = get_se_golomb(gb); + if (pps->cr_qp_offset < -12 || pps->cr_qp_offset > 12) { + av_log(s->avctx, AV_LOG_ERROR, "pps_cr_qp_offset out of range: %d\n", + pps->cr_qp_offset); + ret = AVERROR_INVALIDDATA; + goto err; + } + pps->pic_slice_level_chroma_qp_offsets_present_flag = get_bits1(gb); + + pps->weighted_pred_flag = get_bits1(gb); + pps->weighted_bipred_flag = get_bits1(gb); + + pps->transquant_bypass_enable_flag = get_bits1(gb); + pps->tiles_enabled_flag = get_bits1(gb); + pps->entropy_coding_sync_enabled_flag = get_bits1(gb); + + if (pps->tiles_enabled_flag) { + pps->num_tile_columns = get_ue_golomb_long(gb) + 1; + pps->num_tile_rows = get_ue_golomb_long(gb) + 1; + if (pps->num_tile_columns == 0 || + pps->num_tile_columns >= sps->width) { + av_log(s->avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n", + pps->num_tile_columns - 1); + ret = AVERROR_INVALIDDATA; + goto err; + } + if (pps->num_tile_rows == 0 || + pps->num_tile_rows >= sps->height) { + av_log(s->avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n", + pps->num_tile_rows - 1); + ret = AVERROR_INVALIDDATA; + goto err; + } + + pps->column_width = av_malloc_array(pps->num_tile_columns, sizeof(*pps->column_width)); + pps->row_height = av_malloc_array(pps->num_tile_rows, sizeof(*pps->row_height)); + if (!pps->column_width || !pps->row_height) { + ret = AVERROR(ENOMEM); + goto err; + } + + pps->uniform_spacing_flag = get_bits1(gb); + if (!pps->uniform_spacing_flag) { + uint64_t sum = 0; + for (i = 0; i < pps->num_tile_columns - 1; i++) { + pps->column_width[i] = get_ue_golomb_long(gb) + 1; + sum += pps->column_width[i]; + } + if (sum >= sps->ctb_width) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid tile widths.\n"); + ret = AVERROR_INVALIDDATA; + goto err; + } + pps->column_width[pps->num_tile_columns - 1] = sps->ctb_width - sum; + + sum = 0; + for (i = 0; i < pps->num_tile_rows - 1; i++) { + pps->row_height[i] = get_ue_golomb_long(gb) + 1; + sum += pps->row_height[i]; + } + if (sum >= sps->ctb_height) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid tile heights.\n"); + ret = AVERROR_INVALIDDATA; + goto err; + } + pps->row_height[pps->num_tile_rows - 1] = sps->ctb_height - sum; + } + pps->loop_filter_across_tiles_enabled_flag = get_bits1(gb); + } + + pps->seq_loop_filter_across_slices_enabled_flag = get_bits1(gb); + + pps->deblocking_filter_control_present_flag = get_bits1(gb); + if (pps->deblocking_filter_control_present_flag) { + pps->deblocking_filter_override_enabled_flag = get_bits1(gb); + pps->disable_dbf = get_bits1(gb); + if (!pps->disable_dbf) { + pps->beta_offset = get_se_golomb(gb) * 2; + pps->tc_offset = get_se_golomb(gb) * 2; + if (pps->beta_offset/2 < -6 || pps->beta_offset/2 > 6) { + av_log(s->avctx, AV_LOG_ERROR, "pps_beta_offset_div2 out of range: %d\n", + pps->beta_offset/2); + ret = AVERROR_INVALIDDATA; + goto err; + } + if (pps->tc_offset/2 < -6 || pps->tc_offset/2 > 6) { + av_log(s->avctx, AV_LOG_ERROR, "pps_tc_offset_div2 out of range: %d\n", + pps->tc_offset/2); + ret = AVERROR_INVALIDDATA; + goto err; + } + } + } + + pps->scaling_list_data_present_flag = get_bits1(gb); + if (pps->scaling_list_data_present_flag) { + set_default_scaling_list_data(&pps->scaling_list); + ret = scaling_list_data(s, &pps->scaling_list, sps); + if (ret < 0) + goto err; + } + pps->lists_modification_present_flag = get_bits1(gb); + pps->log2_parallel_merge_level = get_ue_golomb_long(gb) + 2; + if (pps->log2_parallel_merge_level > sps->log2_ctb_size) { + av_log(s->avctx, AV_LOG_ERROR, "log2_parallel_merge_level_minus2 out of range: %d\n", + pps->log2_parallel_merge_level - 2); + ret = AVERROR_INVALIDDATA; + goto err; + } + + pps->slice_header_extension_present_flag = get_bits1(gb); + + if (get_bits1(gb)) { // pps_extension_present_flag + int pps_range_extensions_flag = get_bits1(gb); + /* int pps_extension_7bits = */ get_bits(gb, 7); + if ( +#ifndef USE_MSPS + /* XXX: check if testing the profile is correct */ + sps->ptl.general_ptl.profile_idc == FF_PROFILE_HEVC_REXT && +#endif + pps_range_extensions_flag) { + pps_range_extensions(s, pps, sps); + } + } + + // Inferred parameters + pps->col_bd = av_malloc_array(pps->num_tile_columns + 1, sizeof(*pps->col_bd)); + pps->row_bd = av_malloc_array(pps->num_tile_rows + 1, sizeof(*pps->row_bd)); + pps->col_idxX = av_malloc_array(sps->ctb_width, sizeof(*pps->col_idxX)); + if (!pps->col_bd || !pps->row_bd || !pps->col_idxX) { + ret = AVERROR(ENOMEM); + goto err; + } + + if (pps->uniform_spacing_flag) { + if (!pps->column_width) { + pps->column_width = av_malloc_array(pps->num_tile_columns, sizeof(*pps->column_width)); + pps->row_height = av_malloc_array(pps->num_tile_rows, sizeof(*pps->row_height)); + } + if (!pps->column_width || !pps->row_height) { + ret = AVERROR(ENOMEM); + goto err; + } + + for (i = 0; i < pps->num_tile_columns; i++) { + pps->column_width[i] = ((i + 1) * sps->ctb_width) / pps->num_tile_columns - + (i * sps->ctb_width) / pps->num_tile_columns; + } + + for (i = 0; i < pps->num_tile_rows; i++) { + pps->row_height[i] = ((i + 1) * sps->ctb_height) / pps->num_tile_rows - + (i * sps->ctb_height) / pps->num_tile_rows; + } + } + + pps->col_bd[0] = 0; + for (i = 0; i < pps->num_tile_columns; i++) + pps->col_bd[i + 1] = pps->col_bd[i] + pps->column_width[i]; + + pps->row_bd[0] = 0; + for (i = 0; i < pps->num_tile_rows; i++) + pps->row_bd[i + 1] = pps->row_bd[i] + pps->row_height[i]; + + for (i = 0, j = 0; i < sps->ctb_width; i++) { + if (i > pps->col_bd[j]) + j++; + pps->col_idxX[i] = j; + } + + /** + * 6.5 + */ + pic_area_in_ctbs = sps->ctb_width * sps->ctb_height; + + pps->ctb_addr_rs_to_ts = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->ctb_addr_rs_to_ts)); + pps->ctb_addr_ts_to_rs = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->ctb_addr_ts_to_rs)); + pps->tile_id = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->tile_id)); + pps->min_tb_addr_zs_tab = av_malloc_array((sps->tb_mask+2) * (sps->tb_mask+2), sizeof(*pps->min_tb_addr_zs_tab)); + if (!pps->ctb_addr_rs_to_ts || !pps->ctb_addr_ts_to_rs || + !pps->tile_id || !pps->min_tb_addr_zs_tab) { + ret = AVERROR(ENOMEM); + goto err; + } + + for (ctb_addr_rs = 0; ctb_addr_rs < pic_area_in_ctbs; ctb_addr_rs++) { + int tb_x = ctb_addr_rs % sps->ctb_width; + int tb_y = ctb_addr_rs / sps->ctb_width; + int tile_x = 0; + int tile_y = 0; + int val = 0; + + for (i = 0; i < pps->num_tile_columns; i++) { + if (tb_x < pps->col_bd[i + 1]) { + tile_x = i; + break; + } + } + + for (i = 0; i < pps->num_tile_rows; i++) { + if (tb_y < pps->row_bd[i + 1]) { + tile_y = i; + break; + } + } + + for (i = 0; i < tile_x; i++) + val += pps->row_height[tile_y] * pps->column_width[i]; + for (i = 0; i < tile_y; i++) + val += sps->ctb_width * pps->row_height[i]; + + val += (tb_y - pps->row_bd[tile_y]) * pps->column_width[tile_x] + + tb_x - pps->col_bd[tile_x]; + + pps->ctb_addr_rs_to_ts[ctb_addr_rs] = val; + pps->ctb_addr_ts_to_rs[val] = ctb_addr_rs; + } + + for (j = 0, tile_id = 0; j < pps->num_tile_rows; j++) + for (i = 0; i < pps->num_tile_columns; i++, tile_id++) + for (y = pps->row_bd[j]; y < pps->row_bd[j + 1]; y++) + for (x = pps->col_bd[i]; x < pps->col_bd[i + 1]; x++) + pps->tile_id[pps->ctb_addr_rs_to_ts[y * sps->ctb_width + x]] = tile_id; + + pps->tile_pos_rs = av_malloc_array(tile_id, sizeof(*pps->tile_pos_rs)); + if (!pps->tile_pos_rs) { + ret = AVERROR(ENOMEM); + goto err; + } + + for (j = 0; j < pps->num_tile_rows; j++) + for (i = 0; i < pps->num_tile_columns; i++) + pps->tile_pos_rs[j * pps->num_tile_columns + i] = pps->row_bd[j] * sps->ctb_width + pps->col_bd[i]; + + log2_diff_ctb_min_tb_size = sps->log2_ctb_size - sps->log2_min_tb_size; + pps->min_tb_addr_zs = &pps->min_tb_addr_zs_tab[1*(sps->tb_mask+2)+1]; + for (y = 0; y < sps->tb_mask+2; y++) { + pps->min_tb_addr_zs_tab[y*(sps->tb_mask+2)] = -1; + pps->min_tb_addr_zs_tab[y] = -1; + } + for (y = 0; y < sps->tb_mask+1; y++) { + for (x = 0; x < sps->tb_mask+1; x++) { + int tb_x = x >> log2_diff_ctb_min_tb_size; + int tb_y = y >> log2_diff_ctb_min_tb_size; + int ctb_addr_rs = sps->ctb_width * tb_y + tb_x; + int val = pps->ctb_addr_rs_to_ts[ctb_addr_rs] << + (log2_diff_ctb_min_tb_size * 2); + for (i = 0; i < log2_diff_ctb_min_tb_size; i++) { + int m = 1 << i; + val += (m & x ? m * m : 0) + (m & y ? 2 * m * m : 0); + } + pps->min_tb_addr_zs[y * (sps->tb_mask+2) + x] = val; + } + } + + if (get_bits_left(gb) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Overread PPS by %d bits\n", -get_bits_left(gb)); + goto err; + } + + av_buffer_unref(&s->pps_list[pps_id]); + s->pps_list[pps_id] = pps_buf; + + return 0; + +err: + av_buffer_unref(&pps_buf); + return ret; +} diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c new file mode 100644 index 0000000..e2c1cdf --- /dev/null +++ b/libavcodec/hevc_refs.c @@ -0,0 +1,551 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2012 - 2013 Gildas Cocherel + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/pixdesc.h" + +#include "internal.h" +#include "thread.h" +#include "hevc.h" + +void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags) +{ + /* frame->frame can be NULL if context init failed */ + if (!frame->frame || !frame->frame->buf[0]) + return; + + frame->flags &= ~flags; + if (!frame->flags) { + ff_thread_release_buffer(s->avctx, &frame->tf); + +#ifdef USE_PRED + av_buffer_unref(&frame->tab_mvf_buf); + frame->tab_mvf = NULL; + av_buffer_unref(&frame->rpl_buf); + av_buffer_unref(&frame->rpl_tab_buf); + frame->rpl_tab = NULL; + frame->refPicList = NULL; +#endif + + frame->collocated_ref = NULL; + } +} + +#ifdef USE_PRED +RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0) +{ + int x_cb = x0 >> s->sps->log2_ctb_size; + int y_cb = y0 >> s->sps->log2_ctb_size; + int pic_width_cb = s->sps->ctb_width; + int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb]; + return (RefPicList *)ref->rpl_tab[ctb_addr_ts]; +} +#endif + +void ff_hevc_clear_refs(HEVCContext *s) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) + ff_hevc_unref_frame(s, &s->DPB[i], + HEVC_FRAME_FLAG_SHORT_REF | + HEVC_FRAME_FLAG_LONG_REF); +} + +void ff_hevc_flush_dpb(HEVCContext *s) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) + ff_hevc_unref_frame(s, &s->DPB[i], ~0); +} + +static HEVCFrame *alloc_frame(HEVCContext *s) +{ + int i, j, ret; + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if (frame->frame->buf[0]) + continue; + + ret = ff_thread_get_buffer(s->avctx, &frame->tf, + AV_GET_BUFFER_FLAG_REF); + if (ret < 0) + return NULL; + + frame->ctb_count = s->sps->ctb_width * s->sps->ctb_height; +#ifdef USE_PRED + frame->rpl_buf = av_buffer_allocz(s->nb_nals * sizeof(RefPicListTab)); + if (!frame->rpl_buf) + goto fail; + + frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool); + if (!frame->tab_mvf_buf) + goto fail; + frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data; + + frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool); + if (!frame->rpl_tab_buf) + goto fail; + frame->rpl_tab = (RefPicListTab **)frame->rpl_tab_buf->data; + for (j = 0; j < frame->ctb_count; j++) + frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data; +#endif + + frame->frame->top_field_first = s->picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD; + frame->frame->interlaced_frame = (s->picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) || (s->picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD); + return frame; +fail: + ff_hevc_unref_frame(s, frame, ~0); + return NULL; + } + av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n"); + return NULL; +} + +int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc) +{ + HEVCFrame *ref; + int i; + + /* check that this POC doesn't already exist */ + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + + if (frame->frame->buf[0] && frame->sequence == s->seq_decode && + frame->poc == poc) { + av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n", + poc); + return AVERROR_INVALIDDATA; + } + } + + ref = alloc_frame(s); + if (!ref) + return AVERROR(ENOMEM); + + *frame = ref->frame; + s->ref = ref; + + if (s->sh.pic_output_flag) + ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; + else + ref->flags = HEVC_FRAME_FLAG_SHORT_REF; + + ref->poc = poc; + ref->sequence = s->seq_decode; + ref->window = s->sps->output_window; + + return 0; +} + +int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush) +{ + do { + int nb_output = 0; + int min_poc = INT_MAX; + int i, min_idx, ret; + + if (s->sh.no_output_of_prior_pics_flag == 1) { + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if (!(frame->flags & HEVC_FRAME_FLAG_BUMPING) && frame->poc != s->poc && + frame->sequence == s->seq_output) { + ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT); + } + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) && + frame->sequence == s->seq_output) { + nb_output++; + if (frame->poc < min_poc) { + min_poc = frame->poc; + min_idx = i; + } + } + } + + /* wait for more frames before output */ + if (!flush && s->seq_output == s->seq_decode && s->sps && + nb_output <= s->sps->temporal_layer[s->sps->max_sub_layers - 1].num_reorder_pics) + return 0; + + if (nb_output) { + HEVCFrame *frame = &s->DPB[min_idx]; + AVFrame *src = frame->frame; + + ret = av_frame_ref(out, src); + if (frame->flags & HEVC_FRAME_FLAG_BUMPING) + ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING); + else + ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT); + if (ret < 0) + return ret; + +#ifndef USE_MSPS + { + AVFrame *dst = out; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src->format); + int pixel_shift = !!(desc->comp[0].depth_minus1 > 7); + for (i = 0; i < 3; i++) { + int hshift = (i > 0) ? desc->log2_chroma_w : 0; + int vshift = (i > 0) ? desc->log2_chroma_h : 0; + int off = ((frame->window.left_offset >> hshift) << pixel_shift) + + (frame->window.top_offset >> vshift) * dst->linesize[i]; + dst->data[i] += off; + } + av_log(s->avctx, AV_LOG_DEBUG, + "Output frame with POC %d.\n", frame->poc); + } +#endif + return 1; + } + + if (s->seq_output != s->seq_decode) + s->seq_output = (s->seq_output + 1) & 0xff; + else + break; + } while (1); + + return 0; +} + +#ifdef USE_PRED +void ff_hevc_bump_frame(HEVCContext *s) +{ + int dpb = 0; + int min_poc = INT_MAX; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if ((frame->flags) && + frame->sequence == s->seq_output && + frame->poc != s->poc) { + dpb++; + } + } + + if (s->sps && dpb >= s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering) { + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if ((frame->flags) && + frame->sequence == s->seq_output && + frame->poc != s->poc) { + if (frame->flags == HEVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) { + min_poc = frame->poc; + } + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + if (frame->flags & HEVC_FRAME_FLAG_OUTPUT && + frame->sequence == s->seq_output && + frame->poc <= min_poc) { + frame->flags |= HEVC_FRAME_FLAG_BUMPING; + } + } + + dpb--; + } +} + +static int init_slice_rpl(HEVCContext *s) +{ + HEVCFrame *frame = s->ref; + int ctb_count = frame->ctb_count; + int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr]; + int i; + + if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab)) + return AVERROR_INVALIDDATA; + + for (i = ctb_addr_ts; i < ctb_count; i++) + frame->rpl_tab[i] = (RefPicListTab *)frame->rpl_buf->data + s->slice_idx; + + frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts]; + + return 0; +} + +int ff_hevc_slice_rpl(HEVCContext *s) +{ + SliceHeader *sh = &s->sh; + + uint8_t nb_list = sh->slice_type == B_SLICE ? 2 : 1; + uint8_t list_idx; + int i, j, ret; + + ret = init_slice_rpl(s); + if (ret < 0) + return ret; + + if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs + + s->rps[LT_CURR].nb_refs)) { + av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n"); + return AVERROR_INVALIDDATA; + } + + for (list_idx = 0; list_idx < nb_list; list_idx++) { + RefPicList rpl_tmp = { { 0 } }; + RefPicList *rpl = &s->ref->refPicList[list_idx]; + + /* The order of the elements is + * ST_CURR_BEF - ST_CURR_AFT - LT_CURR for the L0 and + * ST_CURR_AFT - ST_CURR_BEF - LT_CURR for the L1 */ + int cand_lists[3] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF, + list_idx ? ST_CURR_BEF : ST_CURR_AFT, + LT_CURR }; + + /* concatenate the candidate lists for the current frame */ + while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) { + for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) { + RefPicList *rps = &s->rps[cand_lists[i]]; + for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < MAX_REFS; j++) { + rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j]; + rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j]; + rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = i == 2; + rpl_tmp.nb_refs++; + } + } + } + + /* reorder the references if necessary */ + if (sh->rpl_modification_flag[list_idx]) { + for (i = 0; i < sh->nb_refs[list_idx]; i++) { + int idx = sh->list_entry_lx[list_idx][i]; + + if (idx >= rpl_tmp.nb_refs) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n"); + return AVERROR_INVALIDDATA; + } + + rpl->list[i] = rpl_tmp.list[idx]; + rpl->ref[i] = rpl_tmp.ref[idx]; + rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx]; + rpl->nb_refs++; + } + } else { + memcpy(rpl, &rpl_tmp, sizeof(*rpl)); + rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]); + } + + if (sh->collocated_list == list_idx && + sh->collocated_ref_idx < rpl->nb_refs) + s->ref->collocated_ref = rpl->ref[sh->collocated_ref_idx]; + } + + return 0; +} + +static HEVCFrame *find_ref_idx(HEVCContext *s, int poc) +{ + int i; + int LtMask = (1 << s->sps->log2_max_poc_lsb) - 1; + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *ref = &s->DPB[i]; + if (ref->frame->buf[0] && (ref->sequence == s->seq_decode)) { + if ((ref->poc & LtMask) == poc) + return ref; + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *ref = &s->DPB[i]; + if (ref->frame->buf[0] && ref->sequence == s->seq_decode) { + if (ref->poc == poc || (ref->poc & LtMask) == poc) + return ref; + } + } + + av_log(s->avctx, AV_LOG_ERROR, + "Could not find ref with POC %d\n", poc); + return NULL; +} + +static void mark_ref(HEVCFrame *frame, int flag) +{ + frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF); + frame->flags |= flag; +} + +static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) +{ + HEVCFrame *frame; + int i, x, y; + + frame = alloc_frame(s); + if (!frame) + return NULL; + + if (!s->sps->pixel_shift) { + for (i = 0; frame->frame->buf[i]; i++) + memset(frame->frame->buf[i]->data, 1 << (s->sps->bit_depth - 1), + frame->frame->buf[i]->size); + } else { + for (i = 0; frame->frame->data[i]; i++) + for (y = 0; y < (s->sps->height >> s->sps->vshift[i]); y++) + for (x = 0; x < (s->sps->width >> s->sps->hshift[i]); x++) { + AV_WN16(frame->frame->data[i] + y * frame->frame->linesize[i] + 2 * x, + 1 << (s->sps->bit_depth - 1)); + } + } + + frame->poc = poc; + frame->sequence = s->seq_decode; + frame->flags = 0; + + if (s->threads_type == FF_THREAD_FRAME) + ff_thread_report_progress(&frame->tf, INT_MAX, 0); + + return frame; +} + +/* add a reference with the given poc to the list and mark it as used in DPB */ +static int add_candidate_ref(HEVCContext *s, RefPicList *list, + int poc, int ref_flag) +{ + HEVCFrame *ref = find_ref_idx(s, poc); + + if (ref == s->ref) + return AVERROR_INVALIDDATA; + + if (!ref) { + ref = generate_missing_ref(s, poc); + if (!ref) + return AVERROR(ENOMEM); + } + + list->list[list->nb_refs] = ref->poc; + list->ref[list->nb_refs] = ref; + list->nb_refs++; + + mark_ref(ref, ref_flag); + return 0; +} + +int ff_hevc_frame_rps(HEVCContext *s) +{ + const ShortTermRPS *short_rps = s->sh.short_term_rps; + const LongTermRPS *long_rps = &s->sh.long_term_rps; + RefPicList *rps = s->rps; + int i, ret; + + if (!short_rps) { + rps[0].nb_refs = rps[1].nb_refs = 0; + return 0; + } + + /* clear the reference flags on all frames except the current one */ + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + HEVCFrame *frame = &s->DPB[i]; + + if (frame == s->ref) + continue; + + mark_ref(frame, 0); + } + + for (i = 0; i < NB_RPS_TYPE; i++) + rps[i].nb_refs = 0; + + /* add the short refs */ + for (i = 0; i < short_rps->num_delta_pocs; i++) { + int poc = s->poc + short_rps->delta_poc[i]; + int list; + + if (!short_rps->used[i]) + list = ST_FOLL; + else if (i < short_rps->num_negative_pics) + list = ST_CURR_BEF; + else + list = ST_CURR_AFT; + + ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF); + if (ret < 0) + return ret; + } + + /* add the long refs */ + for (i = 0; i < long_rps->nb_refs; i++) { + int poc = long_rps->poc[i]; + int list = long_rps->used[i] ? LT_CURR : LT_FOLL; + + ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF); + if (ret < 0) + return ret; + } + + /* release any frames that are now unused */ + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) + ff_hevc_unref_frame(s, &s->DPB[i], 0); + + return 0; +} + +int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb) +{ + int max_poc_lsb = 1 << s->sps->log2_max_poc_lsb; + int prev_poc_lsb = s->pocTid0 % max_poc_lsb; + int prev_poc_msb = s->pocTid0 - prev_poc_lsb; + int poc_msb; + + if (poc_lsb < prev_poc_lsb && prev_poc_lsb - poc_lsb >= max_poc_lsb / 2) + poc_msb = prev_poc_msb + max_poc_lsb; + else if (poc_lsb > prev_poc_lsb && poc_lsb - prev_poc_lsb > max_poc_lsb / 2) + poc_msb = prev_poc_msb - max_poc_lsb; + else + poc_msb = prev_poc_msb; + + // For BLA picture types, POCmsb is set to 0. + if (s->nal_unit_type == NAL_BLA_W_LP || + s->nal_unit_type == NAL_BLA_W_RADL || + s->nal_unit_type == NAL_BLA_N_LP) + poc_msb = 0; + + return poc_msb + poc_lsb; +} + +int ff_hevc_frame_nb_refs(HEVCContext *s) +{ + int ret = 0; + int i; + const ShortTermRPS *rps = s->sh.short_term_rps; + LongTermRPS *long_rps = &s->sh.long_term_rps; + + if (rps) { + for (i = 0; i < rps->num_negative_pics; i++) + ret += !!rps->used[i]; + for (; i < rps->num_delta_pocs; i++) + ret += !!rps->used[i]; + } + + if (long_rps) { + for (i = 0; i < long_rps->nb_refs; i++) + ret += !!long_rps->used[i]; + } + return ret; +} +#endif diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c new file mode 100644 index 0000000..ffd7b9b --- /dev/null +++ b/libavcodec/hevc_sei.c @@ -0,0 +1,211 @@ +/* + * HEVC Supplementary Enhancement Information messages + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2012 - 2013 Gildas Cocherel + * Copyright (C) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "golomb.h" +#include "hevc.h" + +static void decode_nal_sei_decoded_picture_hash(HEVCContext *s) +{ + int cIdx, i; + uint8_t hash_type; + //uint16_t picture_crc; + //uint32_t picture_checksum; + GetBitContext *gb = &s->HEVClc->gb; + hash_type = get_bits(gb, 8); + + for (cIdx = 0; cIdx < 3/*((s->sps->chroma_format_idc == 0) ? 1 : 3)*/; cIdx++) { + if (hash_type == 0) { + s->is_md5 = 1; + for (i = 0; i < 16; i++) + s->md5[cIdx][i] = get_bits(gb, 8); + } else if (hash_type == 1) { + // picture_crc = get_bits(gb, 16); + skip_bits(gb, 16); + } else if (hash_type == 2) { + // picture_checksum = get_bits_long(gb, 32); + skip_bits(gb, 32); + } + } +} + +#ifdef USE_FULL +static void decode_nal_sei_frame_packing_arrangement(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + + get_ue_golomb(gb); // frame_packing_arrangement_id + s->sei_frame_packing_present = !get_bits1(gb); + + if (s->sei_frame_packing_present) { + s->frame_packing_arrangement_type = get_bits(gb, 7); + s->quincunx_subsampling = get_bits1(gb); + s->content_interpretation_type = get_bits(gb, 6); + + // the following skips spatial_flipping_flag frame0_flipped_flag + // field_views_flag current_frame_is_frame0_flag + // frame0_self_contained_flag frame1_self_contained_flag + skip_bits(gb, 6); + + if (!s->quincunx_subsampling && s->frame_packing_arrangement_type != 5) + skip_bits(gb, 16); // frame[01]_grid_position_[xy] + skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte + skip_bits1(gb); // frame_packing_arrangement_persistance_flag + } + skip_bits1(gb); // upsampled_aspect_ratio_flag +} + +static void decode_nal_sei_display_orientation(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + + s->sei_display_orientation_present = !get_bits1(gb); + + if (s->sei_display_orientation_present) { + s->sei_hflip = get_bits1(gb); // hor_flip + s->sei_vflip = get_bits1(gb); // ver_flip + + s->sei_anticlockwise_rotation = get_bits(gb, 16); + skip_bits1(gb); // display_orientation_persistence_flag + } +} + +static int decode_pic_timing(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + HEVCSPS *sps; + + if (!s->sps_list[s->active_seq_parameter_set_id]) + return(AVERROR(ENOMEM)); + sps = (HEVCSPS*)s->sps_list[s->active_seq_parameter_set_id]->data; + + if (sps->vui.frame_field_info_present_flag) { + int pic_struct = get_bits(gb, 4); + s->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN; + if (pic_struct == 2) { + av_log(s->avctx, AV_LOG_DEBUG, "BOTTOM Field\n"); + s->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; + } else if (pic_struct == 1) { + av_log(s->avctx, AV_LOG_DEBUG, "TOP Field\n"); + s->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD; + } + get_bits(gb, 2); // source_scan_type + get_bits(gb, 1); // duplicate_flag + } + return 1; +} + +static int active_parameter_sets(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + int num_sps_ids_minus1; + int i; + unsigned active_seq_parameter_set_id; + + get_bits(gb, 4); // active_video_parameter_set_id + get_bits(gb, 1); // self_contained_cvs_flag + get_bits(gb, 1); // num_sps_ids_minus1 + num_sps_ids_minus1 = get_ue_golomb_long(gb); // num_sps_ids_minus1 + + active_seq_parameter_set_id = get_ue_golomb_long(gb); + if (active_seq_parameter_set_id >= MAX_SPS_COUNT) { + av_log(s->avctx, AV_LOG_ERROR, "active_parameter_set_id %d invalid\n", active_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + s->active_seq_parameter_set_id = active_seq_parameter_set_id; + + for (i = 1; i <= num_sps_ids_minus1; i++) + get_ue_golomb_long(gb); // active_seq_parameter_set_id[i] + + return 0; +} +#endif + +static int decode_nal_sei_message(HEVCContext *s) +{ + GetBitContext *gb = &s->HEVClc->gb; + + int payload_type = 0; + int payload_size = 0; + int byte = 0xFF; + av_log(s->avctx, AV_LOG_DEBUG, "Decoding SEI\n"); + + while (byte == 0xFF) { + byte = get_bits(gb, 8); + payload_type += byte; + } + byte = 0xFF; + while (byte == 0xFF) { + byte = get_bits(gb, 8); + payload_size += byte; + } + if (s->nal_unit_type == NAL_SEI_PREFIX) { + if (payload_type == 256 /*&& s->decode_checksum_sei*/) { + decode_nal_sei_decoded_picture_hash(s); + } else +#ifdef USE_FULL + if (payload_type == 45) { + decode_nal_sei_frame_packing_arrangement(s); + } else if (payload_type == 47) { + decode_nal_sei_display_orientation(s); + } else if (payload_type == 1){ + int ret = decode_pic_timing(s); + av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type); + skip_bits(gb, 8 * payload_size); + return ret; + } else if (payload_type == 129){ + active_parameter_sets(s); + av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type); + } else +#endif + { + av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type); + skip_bits(gb, 8*payload_size); + } + } else { /* nal_unit_type == NAL_SEI_SUFFIX */ + if (payload_type == 132 /* && s->decode_checksum_sei */) + decode_nal_sei_decoded_picture_hash(s); + else { + av_log(s->avctx, AV_LOG_DEBUG, "Skipped SUFFIX SEI %d\n", payload_type); + skip_bits(gb, 8 * payload_size); + } + } + return 1; +} + +static int more_rbsp_data(GetBitContext *gb) +{ + return get_bits_left(gb) > 0 && show_bits(gb, 8) != 0x80; +} + +int ff_hevc_decode_nal_sei(HEVCContext *s) +{ + int ret; + + do { + ret = decode_nal_sei_message(s); + if (ret < 0) + return(AVERROR(ENOMEM)); + } while (more_rbsp_data(&s->HEVClc->gb)); + return 1; +} diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c new file mode 100644 index 0000000..0fc6638 --- /dev/null +++ b/libavcodec/hevcdsp.c @@ -0,0 +1,340 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere + * + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hevcdsp.h" + +#ifdef CONFIG_SMALL +static int8_t transform[32][32]; + +static const int8_t dct_coefs[32] = { + 64, 90, 90, 90, 89, 88, 87, 85, 83, 82, 80, 78, 75, 73, 70, 67, 64, 61, 57, 54, 50, 46, 43, 38, 36, 31, 25, 22, 18, 13, 9, 4 +}; + +void hevc_transform_init(void) +{ + int i, j, k, s; + + if (transform[0][0]) + return; + for(i = 0; i < 32; i++) { + for(j = 0; j < 32; j++) { + k = (unsigned)((2 * j + 1) * i) % 128; + s = 1; + if (k >= 64) { + k -= 64; + s = -1; + } + if (k >= 32) { + k = 64 - k; + s = -s; + } + transform[i][j] = dct_coefs[k] * s; + } + } +} + +#else +static const int8_t transform[32][32] = { + { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }, + { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4, + -4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90 }, + { 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90, + -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90 }, + { 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13, + 13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90 }, + { 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, + 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 }, + { 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22, + -22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88 }, + { 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87, + -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87 }, + { 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31, + 31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85 }, + { 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, + 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 }, + { 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38, + -38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82 }, + { 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80, + -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80 }, + { 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46, + 46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78 }, + { 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, + 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 }, + { 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54, + -54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73 }, + { 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70, + -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70 }, + { 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61, + 61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67 }, + { 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, + 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 }, + { 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67, + -67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61 }, + { 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57, + -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57 }, + { 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73, + 73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54 }, + { 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, + 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 }, + { 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, + -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46 }, + { 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43, + -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43 }, + { 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82, + 82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38 }, + { 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, + 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 }, + { 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85, + -85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31 }, + { 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25, + -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25 }, + { 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88, + 88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22 }, + { 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, + 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 }, + { 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90, + -90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13 }, + { 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9, + -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9 }, + { 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, + 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 }, +}; +#endif + +DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = { + { -2, 58, 10, -2}, + { -4, 54, 16, -2}, + { -6, 46, 28, -4}, + { -4, 36, 36, -4}, + { -4, 28, 46, -6}, + { -2, 16, 54, -4}, + { -2, 10, 58, -2}, +}; + +DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters[3][16]) = { + { -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0}, + { -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1}, + { 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1} +}; + +#if defined(USE_VAR_BIT_DEPTH) + +#define BIT_DEPTH bit_depth +#include "hevcdsp_template.c" +#undef BIT_DEPTH + +#else + +#define BIT_DEPTH 8 +#include "hevcdsp_template.c" +#undef BIT_DEPTH + +#ifdef USE_FULL +#define BIT_DEPTH 9 +#include "hevcdsp_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 10 +#include "hevcdsp_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 12 +#include "hevcdsp_template.c" +#undef BIT_DEPTH +#endif /* USE_FULL */ + +#endif /* !USE_VAR_BIT_DEPTH */ + +void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth) +{ +#undef FUNC +#define FUNC(a, depth) a ## _ ## depth + +#undef PEL_FUNC +#define PEL_FUNC(dst1, idx1, idx2, a, depth) \ + for(i = 0 ; i < 10 ; i++) \ +{ \ + hevcdsp->dst1[i][idx1][idx2] = a ## _ ## depth; \ +} + +#undef EPEL_FUNCS +#define EPEL_FUNCS(depth) \ + PEL_FUNC(put_hevc_epel, 0, 0, put_hevc_pel_pixels, depth); \ + PEL_FUNC(put_hevc_epel, 0, 1, put_hevc_epel_h, depth); \ + PEL_FUNC(put_hevc_epel, 1, 0, put_hevc_epel_v, depth); \ + PEL_FUNC(put_hevc_epel, 1, 1, put_hevc_epel_hv, depth) + +#undef EPEL_UNI_FUNCS +#define EPEL_UNI_FUNCS(depth) \ + PEL_FUNC(put_hevc_epel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \ + PEL_FUNC(put_hevc_epel_uni, 0, 1, put_hevc_epel_uni_h, depth); \ + PEL_FUNC(put_hevc_epel_uni, 1, 0, put_hevc_epel_uni_v, depth); \ + PEL_FUNC(put_hevc_epel_uni, 1, 1, put_hevc_epel_uni_hv, depth); \ + PEL_FUNC(put_hevc_epel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \ + PEL_FUNC(put_hevc_epel_uni_w, 0, 1, put_hevc_epel_uni_w_h, depth); \ + PEL_FUNC(put_hevc_epel_uni_w, 1, 0, put_hevc_epel_uni_w_v, depth); \ + PEL_FUNC(put_hevc_epel_uni_w, 1, 1, put_hevc_epel_uni_w_hv, depth) + +#undef EPEL_BI_FUNCS +#define EPEL_BI_FUNCS(depth) \ + PEL_FUNC(put_hevc_epel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \ + PEL_FUNC(put_hevc_epel_bi, 0, 1, put_hevc_epel_bi_h, depth); \ + PEL_FUNC(put_hevc_epel_bi, 1, 0, put_hevc_epel_bi_v, depth); \ + PEL_FUNC(put_hevc_epel_bi, 1, 1, put_hevc_epel_bi_hv, depth); \ + PEL_FUNC(put_hevc_epel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \ + PEL_FUNC(put_hevc_epel_bi_w, 0, 1, put_hevc_epel_bi_w_h, depth); \ + PEL_FUNC(put_hevc_epel_bi_w, 1, 0, put_hevc_epel_bi_w_v, depth); \ + PEL_FUNC(put_hevc_epel_bi_w, 1, 1, put_hevc_epel_bi_w_hv, depth) + +#undef QPEL_FUNCS +#define QPEL_FUNCS(depth) \ + PEL_FUNC(put_hevc_qpel, 0, 0, put_hevc_pel_pixels, depth); \ + PEL_FUNC(put_hevc_qpel, 0, 1, put_hevc_qpel_h, depth); \ + PEL_FUNC(put_hevc_qpel, 1, 0, put_hevc_qpel_v, depth); \ + PEL_FUNC(put_hevc_qpel, 1, 1, put_hevc_qpel_hv, depth) + +#undef QPEL_UNI_FUNCS +#define QPEL_UNI_FUNCS(depth) \ + PEL_FUNC(put_hevc_qpel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \ + PEL_FUNC(put_hevc_qpel_uni, 0, 1, put_hevc_qpel_uni_h, depth); \ + PEL_FUNC(put_hevc_qpel_uni, 1, 0, put_hevc_qpel_uni_v, depth); \ + PEL_FUNC(put_hevc_qpel_uni, 1, 1, put_hevc_qpel_uni_hv, depth); \ + PEL_FUNC(put_hevc_qpel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \ + PEL_FUNC(put_hevc_qpel_uni_w, 0, 1, put_hevc_qpel_uni_w_h, depth); \ + PEL_FUNC(put_hevc_qpel_uni_w, 1, 0, put_hevc_qpel_uni_w_v, depth); \ + PEL_FUNC(put_hevc_qpel_uni_w, 1, 1, put_hevc_qpel_uni_w_hv, depth) + +#undef QPEL_BI_FUNCS +#define QPEL_BI_FUNCS(depth) \ + PEL_FUNC(put_hevc_qpel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \ + PEL_FUNC(put_hevc_qpel_bi, 0, 1, put_hevc_qpel_bi_h, depth); \ + PEL_FUNC(put_hevc_qpel_bi, 1, 0, put_hevc_qpel_bi_v, depth); \ + PEL_FUNC(put_hevc_qpel_bi, 1, 1, put_hevc_qpel_bi_hv, depth); \ + PEL_FUNC(put_hevc_qpel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \ + PEL_FUNC(put_hevc_qpel_bi_w, 0, 1, put_hevc_qpel_bi_w_h, depth); \ + PEL_FUNC(put_hevc_qpel_bi_w, 1, 0, put_hevc_qpel_bi_w_v, depth); \ + PEL_FUNC(put_hevc_qpel_bi_w, 1, 1, put_hevc_qpel_bi_w_hv, depth) + +#ifdef USE_PRED +#define HEVC_DSP(depth) \ + hevcdsp->put_pcm = FUNC(put_pcm, depth); \ + hevcdsp->transform_add[0] = FUNC(transform_add4x4, depth); \ + hevcdsp->transform_add[1] = FUNC(transform_add8x8, depth); \ + hevcdsp->transform_add[2] = FUNC(transform_add16x16, depth); \ + hevcdsp->transform_add[3] = FUNC(transform_add32x32, depth); \ + hevcdsp->transform_skip = FUNC(transform_skip, depth); \ + hevcdsp->transform_rdpcm = FUNC(transform_rdpcm, depth); \ + hevcdsp->idct_4x4_luma = FUNC(transform_4x4_luma, depth); \ + hevcdsp->idct[0] = FUNC(idct_4x4, depth); \ + hevcdsp->idct[1] = FUNC(idct_8x8, depth); \ + hevcdsp->idct[2] = FUNC(idct_16x16, depth); \ + hevcdsp->idct[3] = FUNC(idct_32x32, depth); \ + \ + hevcdsp->idct_dc[0] = FUNC(idct_4x4_dc, depth); \ + hevcdsp->idct_dc[1] = FUNC(idct_8x8_dc, depth); \ + hevcdsp->idct_dc[2] = FUNC(idct_16x16_dc, depth); \ + hevcdsp->idct_dc[3] = FUNC(idct_32x32_dc, depth); \ + \ + hevcdsp->sao_band_filter = FUNC(sao_band_filter_0, depth); \ + hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \ + hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \ + \ + QPEL_FUNCS(depth); \ + QPEL_UNI_FUNCS(depth); \ + QPEL_BI_FUNCS(depth); \ + EPEL_FUNCS(depth); \ + EPEL_UNI_FUNCS(depth); \ + EPEL_BI_FUNCS(depth); \ + \ + hevcdsp->hevc_h_loop_filter_luma = FUNC(hevc_h_loop_filter_luma, depth); \ + hevcdsp->hevc_v_loop_filter_luma = FUNC(hevc_v_loop_filter_luma, depth); \ + hevcdsp->hevc_h_loop_filter_chroma = FUNC(hevc_h_loop_filter_chroma, depth); \ + hevcdsp->hevc_v_loop_filter_chroma = FUNC(hevc_v_loop_filter_chroma, depth); \ + hevcdsp->hevc_h_loop_filter_luma_c = FUNC(hevc_h_loop_filter_luma, depth); \ + hevcdsp->hevc_v_loop_filter_luma_c = FUNC(hevc_v_loop_filter_luma, depth); \ + hevcdsp->hevc_h_loop_filter_chroma_c = FUNC(hevc_h_loop_filter_chroma, depth); \ + hevcdsp->hevc_v_loop_filter_chroma_c = FUNC(hevc_v_loop_filter_chroma, depth) +#else +#define HEVC_DSP(depth) \ + hevcdsp->put_pcm = FUNC(put_pcm, depth); \ + hevcdsp->transform_add[0] = FUNC(transform_add4x4, depth); \ + hevcdsp->transform_add[1] = FUNC(transform_add8x8, depth); \ + hevcdsp->transform_add[2] = FUNC(transform_add16x16, depth); \ + hevcdsp->transform_add[3] = FUNC(transform_add32x32, depth); \ + hevcdsp->transform_skip = FUNC(transform_skip, depth); \ + hevcdsp->transform_rdpcm = FUNC(transform_rdpcm, depth); \ + hevcdsp->idct_4x4_luma = FUNC(transform_4x4_luma, depth); \ + hevcdsp->idct[0] = FUNC(idct_4x4, depth); \ + hevcdsp->idct[1] = FUNC(idct_8x8, depth); \ + hevcdsp->idct[2] = FUNC(idct_16x16, depth); \ + hevcdsp->idct[3] = FUNC(idct_32x32, depth); \ + \ + hevcdsp->idct_dc[0] = FUNC(idct_4x4_dc, depth); \ + hevcdsp->idct_dc[1] = FUNC(idct_8x8_dc, depth); \ + hevcdsp->idct_dc[2] = FUNC(idct_16x16_dc, depth); \ + hevcdsp->idct_dc[3] = FUNC(idct_32x32_dc, depth); \ + \ + hevcdsp->sao_band_filter = FUNC(sao_band_filter_0, depth); \ + hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \ + hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \ + \ + hevcdsp->hevc_h_loop_filter_luma = FUNC(hevc_h_loop_filter_luma, depth); \ + hevcdsp->hevc_v_loop_filter_luma = FUNC(hevc_v_loop_filter_luma, depth); \ + hevcdsp->hevc_h_loop_filter_chroma = FUNC(hevc_h_loop_filter_chroma, depth); \ + hevcdsp->hevc_v_loop_filter_chroma = FUNC(hevc_v_loop_filter_chroma, depth); \ + hevcdsp->hevc_h_loop_filter_luma_c = FUNC(hevc_h_loop_filter_luma, depth); \ + hevcdsp->hevc_v_loop_filter_luma_c = FUNC(hevc_v_loop_filter_luma, depth); \ + hevcdsp->hevc_h_loop_filter_chroma_c = FUNC(hevc_h_loop_filter_chroma, depth); \ + hevcdsp->hevc_v_loop_filter_chroma_c = FUNC(hevc_v_loop_filter_chroma, depth) +#endif + +#ifdef USE_PRED +int i = 0; +#endif + +#if defined(USE_VAR_BIT_DEPTH) + HEVC_DSP(var); +#else + switch (bit_depth) { +#ifdef USE_FULL + case 9: + HEVC_DSP(9); + break; + case 10: + HEVC_DSP(10); + break; + case 12: + HEVC_DSP(12); + break; +#endif /* USE_FULL */ + default: + HEVC_DSP(8); + break; + } +#endif /* USE_VAR_BIT_DEPTH */ + + if (ARCH_X86) + ff_hevc_dsp_init_x86(hevcdsp, bit_depth); +} diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h new file mode 100644 index 0000000..af0fefd --- /dev/null +++ b/libavcodec/hevcdsp.h @@ -0,0 +1,144 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere + * + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HEVCDSP_H +#define AVCODEC_HEVCDSP_H + +#include "get_bits.h" + +#define MAX_PB_SIZE 64 + +#ifdef USE_VAR_BIT_DEPTH +#define BIT_DEPTH_PARAM ,int bit_depth +#define BIT_DEPTH_ARG , bit_depth +#define BIT_DEPTH_ARG2(x) , x +#else +#define BIT_DEPTH_PARAM +#define BIT_DEPTH_ARG +#define BIT_DEPTH_ARG2(x) +#endif + +typedef struct SAOParams { + int offset_abs[3][4]; ///< sao_offset_abs + int offset_sign[3][4]; ///< sao_offset_sign + + uint8_t band_position[3]; ///< sao_band_position + + int eo_class[3]; ///< sao_eo_class + + int16_t offset_val[3][5]; /// 0) { + int offset = 1 << (shift - 1); + for (y = 0; y < size; y++) { + for (x = 0; x < size; x++) { + *coeffs = (*coeffs + offset) >> shift; + coeffs++; + } + } + } else { + for (y = 0; y < size; y++) { + for (x = 0; x < size; x++) { + *coeffs = *coeffs << -shift; + coeffs++; + } + } + } +} + +#define SET(dst, x) (dst) = (x) +#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift) +#define ADD_AND_SCALE(dst, x) \ + (dst) = av_clip_pixel((dst) + av_clip_int16(((x) + add) >> shift)) + +#define TR_4x4_LUMA(dst, src, step, assign) \ + do { \ + int c0 = src[0 * step] + src[2 * step]; \ + int c1 = src[2 * step] + src[3 * step]; \ + int c2 = src[0 * step] - src[3 * step]; \ + int c3 = 74 * src[1 * step]; \ + \ + assign(dst[2 * step], 74 * (src[0 * step] - \ + src[2 * step] + \ + src[3 * step])); \ + assign(dst[0 * step], 29 * c0 + 55 * c1 + c3); \ + assign(dst[1 * step], 55 * c2 - 29 * c1 + c3); \ + assign(dst[3 * step], 55 * c0 + 29 * c2 - c3); \ + } while (0) + +static void FUNC(transform_4x4_luma)(int16_t *coeffs BIT_DEPTH_PARAM) +{ + int i; + int shift = 7; + int add = 1 << (shift - 1); + int16_t *src = coeffs; + + for (i = 0; i < 4; i++) { + TR_4x4_LUMA(src, src, 4, SCALE); + src++; + } + + shift = 20 - BIT_DEPTH; + add = 1 << (shift - 1); + for (i = 0; i < 4; i++) { + TR_4x4_LUMA(coeffs, coeffs, 1, SCALE); + coeffs += 4; + } +} + +#undef TR_4x4_LUMA + +#define TR_4(dst, src, dstep, sstep, assign, end) \ + do { \ + const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \ + const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \ + const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \ + const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \ + \ + assign(dst[0 * dstep], e0 + o0); \ + assign(dst[1 * dstep], e1 + o1); \ + assign(dst[2 * dstep], e1 - o1); \ + assign(dst[3 * dstep], e0 - o0); \ + } while (0) + +#define TR_8(dst, src, dstep, sstep, assign, end) \ + do { \ + int i, j; \ + int e_8[4]; \ + int o_8[4] = { 0 }; \ + for (i = 0; i < 4; i++) \ + for (j = 1; j < end; j += 2) \ + o_8[i] += transform[4 * j][i] * src[j * sstep]; \ + TR_4(e_8, src, 1, 2 * sstep, SET, 4); \ + \ + for (i = 0; i < 4; i++) { \ + assign(dst[i * dstep], e_8[i] + o_8[i]); \ + assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]); \ + } \ + } while (0) + +#define TR_16(dst, src, dstep, sstep, assign, end) \ + do { \ + int i, j; \ + int e_16[8]; \ + int o_16[8] = { 0 }; \ + for (i = 0; i < 8; i++) \ + for (j = 1; j < end; j += 2) \ + o_16[i] += transform[2 * j][i] * src[j * sstep]; \ + TR_8(e_16, src, 1, 2 * sstep, SET, 8); \ + \ + for (i = 0; i < 8; i++) { \ + assign(dst[i * dstep], e_16[i] + o_16[i]); \ + assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]); \ + } \ + } while (0) + +#define TR_32(dst, src, dstep, sstep, assign, end) \ + do { \ + int i, j; \ + int e_32[16]; \ + int o_32[16] = { 0 }; \ + for (i = 0; i < 16; i++) \ + for (j = 1; j < end; j += 2) \ + o_32[i] += transform[j][i] * src[j * sstep]; \ + TR_16(e_32, src, 1, 2 * sstep, SET, end/2); \ + \ + for (i = 0; i < 16; i++) { \ + assign(dst[i * dstep], e_32[i] + o_32[i]); \ + assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]); \ + } \ + } while (0) + +#define IDCT_VAR4(H) \ + int limit2 = FFMIN(col_limit + 4, H) +#define IDCT_VAR8(H) \ + int limit = FFMIN(col_limit, H); \ + int limit2 = FFMIN(col_limit + 4, H) +#define IDCT_VAR16(H) IDCT_VAR8(H) +#define IDCT_VAR32(H) IDCT_VAR8(H) + +#define IDCT(H) \ +static void FUNC(idct_##H ##x ##H )( \ + int16_t *coeffs, int col_limit BIT_DEPTH_PARAM) { \ + int i; \ + int shift = 7; \ + int add = 1 << (shift - 1); \ + int16_t *src = coeffs; \ + IDCT_VAR ##H(H); \ + \ + for (i = 0; i < H; i++) { \ + TR_ ## H(src, src, H, H, SCALE, limit2); \ + if (limit2 < H && i%4 == 0 && !!i) \ + limit2 -= 4; \ + src++; \ + } \ + \ + shift = 20 - BIT_DEPTH; \ + add = 1 << (shift - 1); \ + for (i = 0; i < H; i++) { \ + TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit); \ + coeffs += H; \ + } \ +} + +#define IDCT_DC(H) \ +static void FUNC(idct_##H ##x ##H ##_dc)( \ + int16_t *coeffs BIT_DEPTH_PARAM) { \ + int i, j; \ + int shift = 14 - BIT_DEPTH; \ + int add = 1 << (shift - 1); \ + int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift; \ + \ + for (j = 0; j < H; j++) { \ + for (i = 0; i < H; i++) { \ + coeffs[i+j*H] = coeff; \ + } \ + } \ +} + +IDCT( 4) +IDCT( 8) +IDCT(16) +IDCT(32) + +IDCT_DC( 4) +IDCT_DC( 8) +IDCT_DC(16) +IDCT_DC(32) + +#undef TR_4 +#undef TR_8 +#undef TR_16 +#undef TR_32 + +#undef SET +#undef SCALE +#undef ADD_AND_SCALE + +static void FUNC(sao_band_filter_0)(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao, + int *borders, int width, int height, + int c_idx BIT_DEPTH_PARAM) +{ + pixel *dst = (pixel *)_dst; + pixel *src = (pixel *)_src; + int offset_table[32] = { 0 }; + int k, y, x; + int shift = BIT_DEPTH - 5; + int16_t *sao_offset_val = sao->offset_val[c_idx]; + int sao_left_class = sao->band_position[c_idx]; + + stride_dst /= sizeof(pixel); + stride_src /= sizeof(pixel); + + for (k = 0; k < 4; k++) + offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1]; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]); + dst += stride_dst; + src += stride_src; + } +} + +#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1)) + +static void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao, + int width, int height, + int c_idx, int init_x, int init_y BIT_DEPTH_PARAM) { + + static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 }; + static const int8_t pos[4][2][2] = { + { { -1, 0 }, { 1, 0 } }, // horizontal + { { 0, -1 }, { 0, 1 } }, // vertical + { { -1, -1 }, { 1, 1 } }, // 45 degree + { { 1, -1 }, { -1, 1 } }, // 135 degree + }; + int16_t *sao_offset_val = sao->offset_val[c_idx]; + int sao_eo_class = sao->eo_class[c_idx]; + pixel *dst = (pixel *)_dst; + pixel *src = (pixel *)_src; + + int y_stride_src = init_y * stride_src; + int y_stride_dst = init_y * stride_dst; + int pos_0_0 = pos[sao_eo_class][0][0]; + int pos_0_1 = pos[sao_eo_class][0][1]; + int pos_1_0 = pos[sao_eo_class][1][0]; + int pos_1_1 = pos[sao_eo_class][1][1]; + int x, y; + + int y_stride_0_1 = (init_y + pos_0_1) * stride_src; + int y_stride_1_1 = (init_y + pos_1_1) * stride_src; + for (y = init_y; y < height; y++) { + for (x = init_x; x < width; x++) { + int diff0 = CMP(src[x + y_stride_src], src[x + pos_0_0 + y_stride_0_1]); + int diff1 = CMP(src[x + y_stride_src], src[x + pos_1_0 + y_stride_1_1]); + int offset_val = edge_idx[2 + diff0 + diff1]; + dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + sao_offset_val[offset_val]); + } + y_stride_src += stride_src; + y_stride_dst += stride_dst; + y_stride_0_1 += stride_src; + y_stride_1_1 += stride_src; + } +} + +static void FUNC(sao_edge_filter_0)(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao, + int *borders, int _width, int _height, + int c_idx, uint8_t *vert_edge, + uint8_t *horiz_edge, uint8_t *diag_edge BIT_DEPTH_PARAM) +{ + int x, y; + pixel *dst = (pixel *)_dst; + pixel *src = (pixel *)_src; + int16_t *sao_offset_val = sao->offset_val[c_idx]; + int sao_eo_class = sao->eo_class[c_idx]; + int init_x = 0, init_y = 0, width = _width, height = _height; + + stride_dst /= sizeof(pixel); + stride_src /= sizeof(pixel); + + if (sao_eo_class != SAO_EO_VERT) { + if (borders[0]) { + int offset_val = sao_offset_val[0]; + for (y = 0; y < height; y++) { + dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val); + } + init_x = 1; + } + if (borders[2]) { + int offset_val = sao_offset_val[0]; + int offset = width - 1; + for (x = 0; x < height; x++) { + dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val); + } + width--; + } + } + if (sao_eo_class != SAO_EO_HORIZ) { + if (borders[1]) { + int offset_val = sao_offset_val[0]; + for (x = init_x; x < width; x++) + dst[x] = av_clip_pixel(src[x] + offset_val); + init_y = 1; + } + if (borders[3]) { + int offset_val = sao_offset_val[0]; + int y_stride_dst = stride_dst * (height - 1); + int y_stride_src = stride_src * (height - 1); + for (x = init_x; x < width; x++) + dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val); + height--; + } + } + + FUNC(sao_edge_filter)((uint8_t *)dst, (uint8_t *)src, stride_dst, stride_src, sao, width, height, c_idx, init_x, init_y BIT_DEPTH_ARG); +} + +static void FUNC(sao_edge_filter_1)(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao, + int *borders, int _width, int _height, + int c_idx, uint8_t *vert_edge, + uint8_t *horiz_edge, uint8_t *diag_edge BIT_DEPTH_PARAM) +{ + int x, y; + pixel *dst = (pixel *)_dst; + pixel *src = (pixel *)_src; + int16_t *sao_offset_val = sao->offset_val[c_idx]; + int sao_eo_class = sao->eo_class[c_idx]; + int init_x = 0, init_y = 0, width = _width, height = _height; + + stride_dst /= sizeof(pixel); + stride_src /= sizeof(pixel); + + if (sao_eo_class != SAO_EO_VERT) { + if (borders[0]) { + int offset_val = sao_offset_val[0]; + for (y = 0; y < height; y++) { + dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val); + } + init_x = 1; + } + if (borders[2]) { + int offset_val = sao_offset_val[0]; + int offset = width - 1; + for (x = 0; x < height; x++) { + dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val); + } + width--; + } + } + if (sao_eo_class != SAO_EO_HORIZ) { + if (borders[1]) { + int offset_val = sao_offset_val[0]; + for (x = init_x; x < width; x++) + dst[x] = av_clip_pixel(src[x] + offset_val); + init_y = 1; + } + if (borders[3]) { + int offset_val = sao_offset_val[0]; + int y_stride_dst = stride_dst * (height - 1); + int y_stride_src = stride_src * (height - 1); + for (x = init_x; x < width; x++) + dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val); + height--; + } + } + + FUNC(sao_edge_filter)((uint8_t *)dst, (uint8_t *)src, stride_dst, stride_src, sao, width, height, c_idx, init_x, init_y BIT_DEPTH_ARG); + + { + int save_upper_left = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1]; + int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D && !borders[1] && !borders[2]; + int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3]; + int save_lower_left = !diag_edge[3] && sao_eo_class == SAO_EO_45D && !borders[0] && !borders[3]; + + // Restore pixels that can't be modified + if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) { + for(y = init_y+save_upper_left; y< height-save_lower_left; y++) + dst[y*stride_dst] = src[y*stride_src]; + } + if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) { + for(y = init_y+save_upper_right; y< height-save_lower_right; y++) + dst[y*stride_dst+width-1] = src[y*stride_src+width-1]; + } + + if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) { + for(x = init_x+save_upper_left; x < width-save_upper_right; x++) + dst[x] = src[x]; + } + if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) { + for(x = init_x+save_lower_left; x < width-save_lower_right; x++) + dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x]; + } + if(diag_edge[0] && sao_eo_class == SAO_EO_135D) + dst[0] = src[0]; + if(diag_edge[1] && sao_eo_class == SAO_EO_45D) + dst[width-1] = src[width-1]; + if(diag_edge[2] && sao_eo_class == SAO_EO_135D) + dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1]; + if(diag_edge[3] && sao_eo_class == SAO_EO_45D) + dst[stride_dst*(height-1)] = src[stride_src*(height-1)]; + + } +} + +#undef CMP + +#ifdef USE_PRED +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +static void FUNC(put_hevc_pel_pixels)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = src[x] << (14 - BIT_DEPTH); + src += srcstride; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + for (y = 0; y < height; y++) { + memcpy(dst, src, width * sizeof(pixel)); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + dst[x] = av_clip_pixel(( (src[x] << (14 - BIT_DEPTH)) * wx1 + src2[x] * wx0 + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + } + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +#define QPEL_FILTER(src, stride) \ + (filter[0] * src[x - 3 * stride] + \ + filter[1] * src[x - 2 * stride] + \ + filter[2] * src[x - stride] + \ + filter[3] * src[x ] + \ + filter[4] * src[x + stride] + \ + filter[5] * src[x + 2 * stride] + \ + filter[6] * src[x + 3 * stride] + \ + filter[7] * src[x + 4 * stride]) + +static void FUNC(put_hevc_qpel_h)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_v)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[my - 1]; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8); + src += srcstride; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_hv)(int16_t *dst, + uint8_t *_src, + ptrdiff_t _srcstride, + int height, intptr_t mx, + intptr_t my, int width) +{ + int x, y; + const int8_t *filter; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + + src -= QPEL_EXTRA_BEFORE * srcstride; + filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height + QPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_qpel_filters[my - 1]; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6; + tmp += MAX_PB_SIZE; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; + int shift = 14 - BIT_DEPTH; + +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; + + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[my - 1]; + int shift = 14 - BIT_DEPTH; + +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift); + src += srcstride; + dst += dststride; + } +} + + +static void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + const int8_t *filter = ff_hevc_qpel_filters[my - 1]; + + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + const int8_t *filter; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 - BIT_DEPTH; + +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= QPEL_EXTRA_BEFORE * srcstride; + filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height + QPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_qpel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift); + tmp += MAX_PB_SIZE; + dst += dststride; + } +} + +static void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + const int8_t *filter; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= QPEL_EXTRA_BEFORE * srcstride; + filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height + QPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_qpel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift); + tmp += MAX_PB_SIZE; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, + intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; + + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, + intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_qpel_filters[my - 1]; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + + const int8_t *filter = ff_hevc_qpel_filters[my - 1]; + + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, + uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, + intptr_t mx, intptr_t my, int width) +{ + int x, y; + const int8_t *filter; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= QPEL_EXTRA_BEFORE * srcstride; + filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height + QPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_qpel_filters[my - 1]; + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox); + tmp += MAX_PB_SIZE; + dst += dststride; + } +} + +static void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + const int8_t *filter; + pixel *src = (pixel*)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + src -= QPEL_EXTRA_BEFORE * srcstride; + filter = ff_hevc_qpel_filters[mx - 1]; + for (y = 0; y < height + QPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_qpel_filters[my - 1]; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + tmp += MAX_PB_SIZE; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +#define EPEL_FILTER(src, stride) \ + (filter[0] * src[x - stride] + \ + filter[1] * src[x] + \ + filter[2] * src[x + stride] + \ + filter[3] * src[x + 2 * stride]) + +static void FUNC(put_hevc_epel_h)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_v)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8); + src += srcstride; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_hv)(int16_t *dst, + uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + + src -= EPEL_EXTRA_BEFORE * srcstride; + + for (y = 0; y < height + EPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_epel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6; + tmp += MAX_PB_SIZE; + dst += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int shift = 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); + } + dst += dststride; + src += srcstride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[my - 1]; + int shift = 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift); + src += srcstride; + dst += dststride; + } +} + +static void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[my - 1]; + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); + dst += dststride; + src += srcstride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= EPEL_EXTRA_BEFORE * srcstride; + + for (y = 0; y < height + EPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_epel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift); + tmp += MAX_PB_SIZE; + dst += dststride; + } +} + +static void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 + 1 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= EPEL_EXTRA_BEFORE * srcstride; + + for (y = 0; y < height + EPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_epel_filters[my - 1]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift); + tmp += MAX_PB_SIZE; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox); + } + dst += dststride; + src += srcstride; + } +} + +static void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[my - 1]; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox); + } + dst += dststride; + src += srcstride; + } +} + +static void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[my - 1]; + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + src += srcstride; + dst += dststride; + src2 += MAX_PB_SIZE; + } +} + +static void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = denom + 14 - BIT_DEPTH; +#if BIT_DEPTH < 14 + int offset = 1 << (shift - 1); +#else + int offset = 0; +#endif + + src -= EPEL_EXTRA_BEFORE * srcstride; + + for (y = 0; y < height + EPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_epel_filters[my - 1]; + + ox = ox * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox); + tmp += MAX_PB_SIZE; + dst += dststride; + } +} + +static void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, + int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width) +{ + int x, y; + pixel *src = (pixel *)_src; + ptrdiff_t srcstride = _srcstride / sizeof(pixel); + pixel *dst = (pixel *)_dst; + ptrdiff_t dststride = _dststride / sizeof(pixel); + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + int shift = 14 + 1 - BIT_DEPTH; + int log2Wd = denom + shift - 1; + + src -= EPEL_EXTRA_BEFORE * srcstride; + + for (y = 0; y < height + EPEL_EXTRA; y++) { + for (x = 0; x < width; x++) + tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8); + src += srcstride; + tmp += MAX_PB_SIZE; + } + + tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE; + filter = ff_hevc_epel_filters[my - 1]; + + ox0 = ox0 * (1 << (BIT_DEPTH - 8)); + ox1 = ox1 * (1 << (BIT_DEPTH - 8)); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 + + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + tmp += MAX_PB_SIZE; + dst += dststride; + src2 += MAX_PB_SIZE; + } +}// line zero +#endif + + +#define P3 pix[-4 * xstride] +#define P2 pix[-3 * xstride] +#define P1 pix[-2 * xstride] +#define P0 pix[-1 * xstride] +#define Q0 pix[0 * xstride] +#define Q1 pix[1 * xstride] +#define Q2 pix[2 * xstride] +#define Q3 pix[3 * xstride] + +// line three. used only for deblocking decision +#define TP3 pix[-4 * xstride + 3 * ystride] +#define TP2 pix[-3 * xstride + 3 * ystride] +#define TP1 pix[-2 * xstride + 3 * ystride] +#define TP0 pix[-1 * xstride + 3 * ystride] +#define TQ0 pix[0 * xstride + 3 * ystride] +#define TQ1 pix[1 * xstride + 3 * ystride] +#define TQ2 pix[2 * xstride + 3 * ystride] +#define TQ3 pix[3 * xstride + 3 * ystride] + +static void FUNC(hevc_loop_filter_luma)(uint8_t *_pix, + ptrdiff_t _xstride, ptrdiff_t _ystride, + int beta, int *_tc, + uint8_t *_no_p, uint8_t *_no_q BIT_DEPTH_PARAM) +{ + int d, j; + pixel *pix = (pixel *)_pix; + ptrdiff_t xstride = _xstride / sizeof(pixel); + ptrdiff_t ystride = _ystride / sizeof(pixel); + + beta <<= BIT_DEPTH - 8; + + for (j = 0; j < 2; j++) { + const int dp0 = abs(P2 - 2 * P1 + P0); + const int dq0 = abs(Q2 - 2 * Q1 + Q0); + const int dp3 = abs(TP2 - 2 * TP1 + TP0); + const int dq3 = abs(TQ2 - 2 * TQ1 + TQ0); + const int d0 = dp0 + dq0; + const int d3 = dp3 + dq3; + const int tc = _tc[j] << (BIT_DEPTH - 8); + const int no_p = _no_p[j]; + const int no_q = _no_q[j]; + + if (d0 + d3 >= beta) { + pix += 4 * ystride; + continue; + } else { + const int beta_3 = beta >> 3; + const int beta_2 = beta >> 2; + const int tc25 = ((tc * 5 + 1) >> 1); + + if (abs(P3 - P0) + abs(Q3 - Q0) < beta_3 && abs(P0 - Q0) < tc25 && + abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 && + (d0 << 1) < beta_2 && (d3 << 1) < beta_2) { + // strong filtering + const int tc2 = tc << 1; + for (d = 0; d < 4; d++) { + const int p3 = P3; + const int p2 = P2; + const int p1 = P1; + const int p0 = P0; + const int q0 = Q0; + const int q1 = Q1; + const int q2 = Q2; + const int q3 = Q3; + if (!no_p) { + P0 = p0 + av_clip(((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) - p0, -tc2, tc2); + P1 = p1 + av_clip(((p2 + p1 + p0 + q0 + 2) >> 2) - p1, -tc2, tc2); + P2 = p2 + av_clip(((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) - p2, -tc2, tc2); + } + if (!no_q) { + Q0 = q0 + av_clip(((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) - q0, -tc2, tc2); + Q1 = q1 + av_clip(((p0 + q0 + q1 + q2 + 2) >> 2) - q1, -tc2, tc2); + Q2 = q2 + av_clip(((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) - q2, -tc2, tc2); + } + pix += ystride; + } + } else { // normal filtering + int nd_p = 1; + int nd_q = 1; + const int tc_2 = tc >> 1; + if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3)) + nd_p = 2; + if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3)) + nd_q = 2; + + for (d = 0; d < 4; d++) { + const int p2 = P2; + const int p1 = P1; + const int p0 = P0; + const int q0 = Q0; + const int q1 = Q1; + const int q2 = Q2; + int delta0 = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4; + if (abs(delta0) < 10 * tc) { + delta0 = av_clip(delta0, -tc, tc); + if (!no_p) + P0 = av_clip_pixel(p0 + delta0); + if (!no_q) + Q0 = av_clip_pixel(q0 - delta0); + if (!no_p && nd_p > 1) { + const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2); + P1 = av_clip_pixel(p1 + deltap1); + } + if (!no_q && nd_q > 1) { + const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2); + Q1 = av_clip_pixel(q1 + deltaq1); + } + } + pix += ystride; + } + } + } + } +} + +static void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride, + ptrdiff_t _ystride, int *_tc, + uint8_t *_no_p, uint8_t *_no_q BIT_DEPTH_PARAM) +{ + int d, j, no_p, no_q; + pixel *pix = (pixel *)_pix; + ptrdiff_t xstride = _xstride / sizeof(pixel); + ptrdiff_t ystride = _ystride / sizeof(pixel); + + for (j = 0; j < 2; j++) { + const int tc = _tc[j] << (BIT_DEPTH - 8); + if (tc <= 0) { + pix += 4 * ystride; + continue; + } + no_p = _no_p[j]; + no_q = _no_q[j]; + + for (d = 0; d < 4; d++) { + int delta0; + const int p1 = P1; + const int p0 = P0; + const int q0 = Q0; + const int q1 = Q1; + delta0 = av_clip((((q0 - p0) * 4) + p1 - q1 + 4) >> 3, -tc, tc); + if (!no_p) + P0 = av_clip_pixel(p0 + delta0); + if (!no_q) + Q0 = av_clip_pixel(q0 - delta0); + pix += ystride; + } + } +} + +static void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride, + int32_t *tc, uint8_t *no_p, + uint8_t *no_q BIT_DEPTH_PARAM) +{ + FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q BIT_DEPTH_ARG); +} + +static void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride, + int32_t *tc, uint8_t *no_p, + uint8_t *no_q BIT_DEPTH_PARAM) +{ + FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q BIT_DEPTH_ARG); +} + +static void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride, + int beta, int32_t *tc, uint8_t *no_p, + uint8_t *no_q BIT_DEPTH_PARAM) +{ + FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel), + beta, tc, no_p, no_q BIT_DEPTH_ARG); +} + +static void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride, + int beta, int32_t *tc, uint8_t *no_p, + uint8_t *no_q BIT_DEPTH_PARAM) +{ + FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride, + beta, tc, no_p, no_q BIT_DEPTH_ARG); +} + +#undef P3 +#undef P2 +#undef P1 +#undef P0 +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 + +#undef TP3 +#undef TP2 +#undef TP1 +#undef TP0 +#undef TQ0 +#undef TQ1 +#undef TQ2 +#undef TQ3 diff --git a/libavcodec/hevcpred.c b/libavcodec/hevcpred.c new file mode 100644 index 0000000..8ba005a --- /dev/null +++ b/libavcodec/hevcpred.c @@ -0,0 +1,104 @@ +/* + * HEVC video Decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hevc.h" + +#include "hevcpred.h" + +#if defined(USE_FULL) +#define HEVC_INLINE av_always_inline +#else +/* Note: slower but smaller */ +#define HEVC_INLINE av_noinline +#endif + +#ifdef USE_VAR_BIT_DEPTH + +#define BIT_DEPTH bit_depth +#include "hevcpred_template.c" +#undef BIT_DEPTH + +#else + +#define BIT_DEPTH 8 +#include "hevcpred_template.c" +#undef BIT_DEPTH + +#ifdef USE_FULL +#define BIT_DEPTH 9 +#include "hevcpred_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 10 +#include "hevcpred_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 12 +#include "hevcpred_template.c" +#undef BIT_DEPTH +#endif /* USE_FULL */ + +#endif /* USE_VAR_BIT_DEPTH */ + +#ifdef USE_FUNC_PTR +void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth) +{ +#undef FUNC +#define FUNC(a, depth) a ## _ ## depth + +#define HEVC_PRED(depth) \ + hpc->intra_pred[0] = FUNC(intra_pred_2, depth); \ + hpc->intra_pred[1] = FUNC(intra_pred_3, depth); \ + hpc->intra_pred[2] = FUNC(intra_pred_4, depth); \ + hpc->intra_pred[3] = FUNC(intra_pred_5, depth); \ + hpc->pred_planar[0] = FUNC(pred_planar_0, depth); \ + hpc->pred_planar[1] = FUNC(pred_planar_1, depth); \ + hpc->pred_planar[2] = FUNC(pred_planar_2, depth); \ + hpc->pred_planar[3] = FUNC(pred_planar_3, depth); \ + hpc->pred_dc = FUNC(pred_dc, depth); \ + hpc->pred_angular[0] = FUNC(pred_angular_0, depth); \ + hpc->pred_angular[1] = FUNC(pred_angular_1, depth); \ + hpc->pred_angular[2] = FUNC(pred_angular_2, depth); \ + hpc->pred_angular[3] = FUNC(pred_angular_3, depth); + +#ifdef USE_VAR_BIT_DEPTH + HEVC_PRED(var); +#else + switch (bit_depth) { +#ifdef USE_FULL + case 9: + HEVC_PRED(9); + break; + case 10: + HEVC_PRED(10); + break; + case 12: + HEVC_PRED(12); + break; +#endif /* USE_FULL */ + default: + HEVC_PRED(8); + break; + } +#endif /* !USE_VAR_BIT_DEPTH */ +} +#endif diff --git a/libavcodec/hevcpred.h b/libavcodec/hevcpred.h new file mode 100644 index 0000000..ce1d88e --- /dev/null +++ b/libavcodec/hevcpred.h @@ -0,0 +1,46 @@ +/* + * HEVC video Decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HEVCPRED_H +#define AVCODEC_HEVCPRED_H + +#include +#include + +struct HEVCContext; + +typedef struct HEVCPredContext { + void (*intra_pred[4])(struct HEVCContext *s, int x0, int y0, int c_idx); + + void (*pred_planar[4])(uint8_t *src, const uint8_t *top, + const uint8_t *left, ptrdiff_t stride); + void (*pred_dc)(uint8_t *src, const uint8_t *top, const uint8_t *left, + ptrdiff_t stride, int log2_size, int c_idx); + void (*pred_angular[4])(uint8_t *src, const uint8_t *top, + const uint8_t *left, ptrdiff_t stride, + int c_idx, int mode, + int disable_intra_boundary_filter BIT_DEPTH_PARAM); +} HEVCPredContext; + +void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth); + +#endif /* AVCODEC_HEVCPRED_H */ diff --git a/libavcodec/hevcpred_template.c b/libavcodec/hevcpred_template.c new file mode 100644 index 0000000..bf77d46 --- /dev/null +++ b/libavcodec/hevcpred_template.c @@ -0,0 +1,620 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/pixdesc.h" + +#include "bit_depth_template.c" +#include "hevcpred.h" + +#ifndef USE_FUNC_PTR +static HEVC_INLINE void FUNC(pred_planar)(uint8_t *_src, const uint8_t *_top, + const uint8_t *_left, ptrdiff_t stride, + int trafo_size); +static void FUNC(pred_dc)(uint8_t *_src, const uint8_t *_top, + const uint8_t *_left, + ptrdiff_t stride, int log2_size, int c_idx); +static HEVC_INLINE void FUNC(pred_angular)(uint8_t *_src, + const uint8_t *_top, + const uint8_t *_left, + ptrdiff_t stride, int c_idx, + int mode, int size, + int disable_intra_boundary_filter BIT_DEPTH_PARAM); +#endif + +#define POS(x, y) src[(x) + stride * (y)] + +#ifdef USE_FUNC_PTR +static HEVC_INLINE void FUNC(intra_pred) +#else +void intra_pred +#endif +(HEVCContext *s, int x0, int y0, int log2_size, int c_idx) +{ +#define PU(x) \ + ((x) >> s->sps->log2_min_pu_size) +#ifdef USE_PRED +#define MVF(x, y) \ + (s->ref->tab_mvf[(x) + (y) * min_pu_width].pred_flag) +#else +#define MVF(x, y) PF_INTRA +#endif +#define MVF_PU(x, y) \ + MVF(PU(x0 + ((x) << hshift)), PU(y0 + ((y) << vshift))) +#define IS_INTRA(x, y) \ + (MVF_PU(x, y) == PF_INTRA) +#define MIN_TB_ADDR_ZS(x, y) \ + s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)] +#define EXTEND(ptr, val, len) \ +do { \ + pixel4 pix = PIXEL_SPLAT_X4(val); \ + for (i = 0; i < (len); i += 4) \ + AV_WN4P(ptr + i, pix); \ +} while (0) + +#define EXTEND_RIGHT_CIP(ptr, start, length) \ + for (i = start; i < (start) + (length); i += 4) \ + if (!IS_INTRA(i, -1)) \ + AV_WN4P(&ptr[i], a); \ + else \ + a = PIXEL_SPLAT_X4(ptr[i+3]) +#define EXTEND_LEFT_CIP(ptr, start, length) \ + for (i = start; i > (start) - (length); i--) \ + if (!IS_INTRA(i - 1, -1)) \ + ptr[i - 1] = ptr[i] +#define EXTEND_UP_CIP(ptr, start, length) \ + for (i = (start); i > (start) - (length); i -= 4) \ + if (!IS_INTRA(-1, i - 3)) \ + AV_WN4P(&ptr[i - 3], a); \ + else \ + a = PIXEL_SPLAT_X4(ptr[i - 3]) +#define EXTEND_DOWN_CIP(ptr, start, length) \ + for (i = start; i < (start) + (length); i += 4) \ + if (!IS_INTRA(-1, i)) \ + AV_WN4P(&ptr[i], a); \ + else \ + a = PIXEL_SPLAT_X4(ptr[i + 3]) + + HEVCLocalContext *lc = s->HEVClc; +#ifdef USE_VAR_BIT_DEPTH + int bit_depth = s->sps->bit_depth; +#endif + int i; + int hshift = s->sps->hshift[c_idx]; + int vshift = s->sps->vshift[c_idx]; + int size = (1 << log2_size); + int size_in_luma_h = size << hshift; + int size_in_tbs_h = size_in_luma_h >> s->sps->log2_min_tb_size; + int size_in_luma_v = size << vshift; + int size_in_tbs_v = size_in_luma_v >> s->sps->log2_min_tb_size; + int x = x0 >> hshift; + int y = y0 >> vshift; + int x_tb = (x0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask; + int y_tb = (y0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask; + + int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb); + + ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel); + pixel *src = (pixel*)s->frame->data[c_idx] + x + y * stride; + + int min_pu_width = s->sps->min_pu_width; + + enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c : + lc->tu.intra_pred_mode; + pixel4 a; + pixel left_array[2 * MAX_TB_SIZE + 1]; + pixel filtered_left_array[2 * MAX_TB_SIZE + 1]; + pixel top_array[2 * MAX_TB_SIZE + 1]; + pixel filtered_top_array[2 * MAX_TB_SIZE + 1]; + + pixel *left = left_array + 1; + pixel *top = top_array + 1; + pixel *filtered_left = filtered_left_array + 1; + pixel *filtered_top = filtered_top_array + 1; + int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v) & s->sps->tb_mask); + int cand_left = lc->na.cand_left; + int cand_up_left = lc->na.cand_up_left; + int cand_up = lc->na.cand_up; + int cand_up_right = lc->na.cand_up_right && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & s->sps->tb_mask, y_tb - 1); + + int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, s->sps->height) - + (y0 + size_in_luma_v)) >> vshift; + int top_right_size = (FFMIN(x0 + 2 * size_in_luma_h, s->sps->width) - + (x0 + size_in_luma_h)) >> hshift; + int disable_intra_boundary_filter; + + if (s->pps->constrained_intra_pred_flag == 1) { + int size_in_luma_pu_v = PU(size_in_luma_v); + int size_in_luma_pu_h = PU(size_in_luma_h); + int on_pu_edge_x = !(x0 & ((1 << s->sps->log2_min_pu_size) - 1)); + int on_pu_edge_y = !(y0 & ((1 << s->sps->log2_min_pu_size) - 1)); + if (!size_in_luma_pu_h) + size_in_luma_pu_h++; + if (cand_bottom_left == 1 && on_pu_edge_x) { + int x_left_pu = PU(x0 - 1); + int y_bottom_pu = PU(y0 + size_in_luma_v); + int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_bottom_pu); + cand_bottom_left = 0; + for (i = 0; i < max; i += 2) + cand_bottom_left |= (MVF(x_left_pu, y_bottom_pu + i) == PF_INTRA); + } + if (cand_left == 1 && on_pu_edge_x) { + int x_left_pu = PU(x0 - 1); + int y_left_pu = PU(y0); + int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_left_pu); + cand_left = 0; + for (i = 0; i < max; i += 2) + cand_left |= (MVF(x_left_pu, y_left_pu + i) == PF_INTRA); + } + if (cand_up_left == 1) { + int x_left_pu = PU(x0 - 1); + int y_top_pu = PU(y0 - 1); + cand_up_left = MVF(x_left_pu, y_top_pu) == PF_INTRA; + } + if (cand_up == 1 && on_pu_edge_y) { + int x_top_pu = PU(x0); + int y_top_pu = PU(y0 - 1); + int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_top_pu); + cand_up = 0; + for (i = 0; i < max; i += 2) + cand_up |= (MVF(x_top_pu + i, y_top_pu) == PF_INTRA); + } + if (cand_up_right == 1 && on_pu_edge_y) { + int y_top_pu = PU(y0 - 1); + int x_right_pu = PU(x0 + size_in_luma_h); + int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_right_pu); + cand_up_right = 0; + for (i = 0; i < max; i += 2) + cand_up_right |= (MVF(x_right_pu + i, y_top_pu) == PF_INTRA); + } + memset(left, 128, 2 * MAX_TB_SIZE*sizeof(pixel)); + memset(top , 128, 2 * MAX_TB_SIZE*sizeof(pixel)); + top[-1] = 128; + } + if (cand_up_left) { + left[-1] = POS(-1, -1); + top[-1] = left[-1]; + } + if (cand_up) + memcpy(top, src - stride, size * sizeof(pixel)); + if (cand_up_right) { + memcpy(top + size, src - stride + size, size * sizeof(pixel)); + EXTEND(top + size + top_right_size, POS(size + top_right_size - 1, -1), + size - top_right_size); + } + if (cand_left) + for (i = 0; i < size; i++) + left[i] = POS(-1, i); + if (cand_bottom_left) { + for (i = size; i < size + bottom_left_size; i++) + left[i] = POS(-1, i); + EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1), + size - bottom_left_size); + } + + if (s->pps->constrained_intra_pred_flag == 1) { + if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) { + int size_max_x = x0 + ((2 * size) << hshift) < s->sps->width ? + 2 * size : (s->sps->width - x0) >> hshift; + int size_max_y = y0 + ((2 * size) << vshift) < s->sps->height ? + 2 * size : (s->sps->height - y0) >> vshift; + int j = size + (cand_bottom_left? bottom_left_size: 0) -1; + if (!cand_up_right) { + size_max_x = x0 + ((size) << hshift) < s->sps->width ? + size : (s->sps->width - x0) >> hshift; + } + if (!cand_bottom_left) { + size_max_y = y0 + (( size) << vshift) < s->sps->height ? + size : (s->sps->height - y0) >> vshift; + } + if (cand_bottom_left || cand_left || cand_up_left) { + while (j > -1 && !IS_INTRA(-1, j)) + j--; + if (!IS_INTRA(-1, j)) { + j = 0; + while (j < size_max_x && !IS_INTRA(j, -1)) + j++; + EXTEND_LEFT_CIP(top, j, j + 1); + left[-1] = top[-1]; + } + } else { + j = 0; + while (j < size_max_x && !IS_INTRA(j, -1)) + j++; + if (j > 0) + if (x0 > 0) { + EXTEND_LEFT_CIP(top, j, j + 1); + } else { + EXTEND_LEFT_CIP(top, j, j); + top[-1] = top[0]; + } + left[-1] = top[-1]; + } + left[-1] = top[-1]; + if (cand_bottom_left || cand_left) { + a = PIXEL_SPLAT_X4(left[-1]); + EXTEND_DOWN_CIP(left, 0, size_max_y); + } + if (!cand_left) + EXTEND(left, left[-1], size); + if (!cand_bottom_left) + EXTEND(left + size, left[size - 1], size); + if (x0 != 0 && y0 != 0) { + a = PIXEL_SPLAT_X4(left[size_max_y - 1]); + EXTEND_UP_CIP(left, size_max_y - 1, size_max_y); + if (!IS_INTRA(-1, - 1)) + left[-1] = left[0]; + } else if (x0 == 0) { + EXTEND(left, 0, size_max_y); + } else { + a = PIXEL_SPLAT_X4(left[size_max_y - 1]); + EXTEND_UP_CIP(left, size_max_y - 1, size_max_y); + } + top[-1] = left[-1]; + if (y0 != 0) { + a = PIXEL_SPLAT_X4(left[-1]); + EXTEND_RIGHT_CIP(top, 0, size_max_x); + } + } + } + // Infer the unavailable samples + if (!cand_bottom_left) { + if (cand_left) { + EXTEND(left + size, left[size - 1], size); + } else if (cand_up_left) { + EXTEND(left, left[-1], 2 * size); + cand_left = 1; + } else if (cand_up) { + left[-1] = top[0]; + EXTEND(left, left[-1], 2 * size); + cand_up_left = 1; + cand_left = 1; + } else if (cand_up_right) { + EXTEND(top, top[size], size); + left[-1] = top[size]; + EXTEND(left, left[-1], 2 * size); + cand_up = 1; + cand_up_left = 1; + cand_left = 1; + } else { // No samples available + left[-1] = (1 << (BIT_DEPTH - 1)); + EXTEND(top, left[-1], 2 * size); + EXTEND(left, left[-1], 2 * size); + } + } + + if (!cand_left) + EXTEND(left, left[size], size); + if (!cand_up_left) { + left[-1] = left[0]; + } + if (!cand_up) + EXTEND(top, left[-1], size); + if (!cand_up_right) + EXTEND(top + size, top[size - 1], size); + + top[-1] = left[-1]; + + // Filtering process + if (!s->sps->intra_smoothing_disabled_flag && (c_idx == 0 || s->sps->chroma_format_idc == 3)) { + if (mode != INTRA_DC && size != 4){ + int intra_hor_ver_dist_thresh[] = { 7, 1, 0 }; + int min_dist_vert_hor = FFMIN(FFABS((int)(mode - 26U)), + FFABS((int)(mode - 10U))); + if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) { + int threshold = 1 << (BIT_DEPTH - 5); + if (s->sps->sps_strong_intra_smoothing_enable_flag && c_idx == 0 && + log2_size == 5 && + FFABS(top[-1] + top[63] - 2 * top[31]) < threshold && + FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) { + // We can't just overwrite values in top because it could be + // a pointer into src + filtered_top[-1] = top[-1]; + filtered_top[63] = top[63]; + for (i = 0; i < 63; i++) + filtered_top[i] = ((64 - (i + 1)) * top[-1] + + (i + 1) * top[63] + 32) >> 6; + for (i = 0; i < 63; i++) + left[i] = ((64 - (i + 1)) * left[-1] + + (i + 1) * left[63] + 32) >> 6; + top = filtered_top; + } else { + filtered_left[2 * size - 1] = left[2 * size - 1]; + filtered_top[2 * size - 1] = top[2 * size - 1]; + for (i = 2 * size - 2; i >= 0; i--) + filtered_left[i] = (left[i + 1] + 2 * left[i] + + left[i - 1] + 2) >> 2; + filtered_top[-1] = + filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2; + for (i = 2 * size - 2; i >= 0; i--) + filtered_top[i] = (top[i + 1] + 2 * top[i] + + top[i - 1] + 2) >> 2; + left = filtered_left; + top = filtered_top; + } + } + } + } + + switch (mode) { + case INTRA_PLANAR: +#ifdef USE_FUNC_PTR + s->hpc.pred_planar[log2_size - 2]((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride); +#else + FUNC(pred_planar)((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride, log2_size); +#endif + break; + case INTRA_DC: +#ifdef USE_FUNC_PTR + s->hpc.pred_dc((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride, log2_size, c_idx); +#else + FUNC(pred_dc)((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride, log2_size, c_idx); +#endif + break; + default: + disable_intra_boundary_filter = (s->sps->implicit_rdpcm_enabled_flag && + lc->cu.cu_transquant_bypass_flag); +#ifdef USE_FUNC_PTR + s->hpc.pred_angular[log2_size - 2]((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride, c_idx, + mode, + disable_intra_boundary_filter BIT_DEPTH_ARG); +#else + FUNC(pred_angular)((uint8_t *)src, (uint8_t *)top, + (uint8_t *)left, stride, c_idx, + mode, 1 << log2_size, + disable_intra_boundary_filter BIT_DEPTH_ARG); +#endif + break; + } +} + +#ifdef USE_FUNC_PTR + +#define INTRA_PRED(size) \ +static void FUNC(intra_pred_ ## size)(HEVCContext *s, int x0, int y0, int c_idx) \ +{ \ + FUNC(intra_pred)(s, x0, y0, size, c_idx); \ +} + +INTRA_PRED(2) +INTRA_PRED(3) +INTRA_PRED(4) +INTRA_PRED(5) + +#undef INTRA_PRED + +#endif + +static HEVC_INLINE void FUNC(pred_planar)(uint8_t *_src, const uint8_t *_top, + const uint8_t *_left, ptrdiff_t stride, + int trafo_size) +{ + int x, y; + pixel *src = (pixel *)_src; + const pixel *top = (const pixel *)_top; + const pixel *left = (const pixel *)_left; + int size = 1 << trafo_size; + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + POS(x, y) = ((size - 1 - x) * left[y] + (x + 1) * top[size] + + (size - 1 - y) * top[x] + (y + 1) * left[size] + size) >> (trafo_size + 1); +} + +#ifdef USE_FUNC_PTR + +#define PRED_PLANAR(size)\ +static void FUNC(pred_planar_ ## size)(uint8_t *src, const uint8_t *top, \ + const uint8_t *left, ptrdiff_t stride) \ +{ \ + FUNC(pred_planar)(src, top, left, stride, size + 2); \ +} + +PRED_PLANAR(0) +PRED_PLANAR(1) +PRED_PLANAR(2) +PRED_PLANAR(3) + +#undef PRED_PLANAR + +#endif + +static void FUNC(pred_dc)(uint8_t *_src, const uint8_t *_top, + const uint8_t *_left, + ptrdiff_t stride, int log2_size, int c_idx) +{ + int i, j, x, y; + int size = (1 << log2_size); + pixel *src = (pixel *)_src; + const pixel *top = (const pixel *)_top; + const pixel *left = (const pixel *)_left; + int dc = size; + pixel4 a; + for (i = 0; i < size; i++) + dc += left[i] + top[i]; + + dc >>= log2_size + 1; + + a = PIXEL_SPLAT_X4(dc); + + for (i = 0; i < size; i++) + for (j = 0; j < size; j+=4) + AV_WN4P(&POS(j, i), a); + + if (c_idx == 0 && size < 32) { + POS(0, 0) = (left[0] + 2 * dc + top[0] + 2) >> 2; + for (x = 1; x < size; x++) + POS(x, 0) = (top[x] + 3 * dc + 2) >> 2; + for (y = 1; y < size; y++) + POS(0, y) = (left[y] + 3 * dc + 2) >> 2; + } +} + +static HEVC_INLINE void FUNC(pred_angular)(uint8_t *_src, + const uint8_t *_top, + const uint8_t *_left, + ptrdiff_t stride, int c_idx, + int mode, int size, + int disable_intra_boundary_filter BIT_DEPTH_PARAM) +{ + int x, y; + pixel *src = (pixel *)_src; + const pixel *top = (const pixel *)_top; + const pixel *left = (const pixel *)_left; + + static const int8_t intra_pred_angle[] = { + 32, 26, 21, 17, 13, 9, 5, 2, 0, -2, -5, -9, -13, -17, -21, -26, -32, + -26, -21, -17, -13, -9, -5, -2, 0, 2, 5, 9, 13, 17, 21, 26, 32 + }; + static const int16_t inv_angle[] = { + -4096, -1638, -910, -630, -482, -390, -315, -256, -315, -390, -482, + -630, -910, -1638, -4096 + }; + + int angle = intra_pred_angle[mode - 2]; + pixel ref_array[3 * MAX_TB_SIZE + 4]; + pixel *ref_tmp = ref_array + size; + const pixel *ref; + int last = (size * angle) >> 5; + + if (mode >= 18) { + ref = top - 1; + if (angle < 0 && last < -1) { + for (x = 0; x <= size; x += 4) + AV_WN4P(&ref_tmp[x], AV_RN4P(&top[x - 1])); + for (x = last; x <= -1; x++) + ref_tmp[x] = left[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)]; + ref = ref_tmp; + } + + for (y = 0; y < size; y++) { + int idx = ((y + 1) * angle) >> 5; + int fact = ((y + 1) * angle) & 31; + if (fact) { + for (x = 0; x < size; x += 4) { + POS(x , y) = ((32 - fact) * ref[x + idx + 1] + + fact * ref[x + idx + 2] + 16) >> 5; + POS(x + 1, y) = ((32 - fact) * ref[x + 1 + idx + 1] + + fact * ref[x + 1 + idx + 2] + 16) >> 5; + POS(x + 2, y) = ((32 - fact) * ref[x + 2 + idx + 1] + + fact * ref[x + 2 + idx + 2] + 16) >> 5; + POS(x + 3, y) = ((32 - fact) * ref[x + 3 + idx + 1] + + fact * ref[x + 3 + idx + 2] + 16) >> 5; + } + } else { + for (x = 0; x < size; x += 4) + AV_WN4P(&POS(x, y), AV_RN4P(&ref[x + idx + 1])); + } + } + if (mode == 26 && c_idx == 0 && size < 32 && + !disable_intra_boundary_filter) { + for (y = 0; y < size; y++) + POS(0, y) = av_clip_pixel(top[0] + ((left[y] - left[-1]) >> 1)); + } + } else { + ref = left - 1; + if (angle < 0 && last < -1) { + for (x = 0; x <= size; x += 4) + AV_WN4P(&ref_tmp[x], AV_RN4P(&left[x - 1])); + for (x = last; x <= -1; x++) + ref_tmp[x] = top[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)]; + ref = ref_tmp; + } + + for (x = 0; x < size; x++) { + int idx = ((x + 1) * angle) >> 5; + int fact = ((x + 1) * angle) & 31; + if (fact) { + for (y = 0; y < size; y++) { + POS(x, y) = ((32 - fact) * ref[y + idx + 1] + + fact * ref[y + idx + 2] + 16) >> 5; + } + } else { + for (y = 0; y < size; y++) + POS(x, y) = ref[y + idx + 1]; + } + } + if (mode == 10 && c_idx == 0 && size < 32 && + !disable_intra_boundary_filter) { + for (x = 0; x < size; x += 4) { + POS(x, 0) = av_clip_pixel(left[0] + ((top[x ] - top[-1]) >> 1)); + POS(x + 1, 0) = av_clip_pixel(left[0] + ((top[x + 1] - top[-1]) >> 1)); + POS(x + 2, 0) = av_clip_pixel(left[0] + ((top[x + 2] - top[-1]) >> 1)); + POS(x + 3, 0) = av_clip_pixel(left[0] + ((top[x + 3] - top[-1]) >> 1)); + } + } + } +} + +#ifdef USE_FUNC_PTR + +static void FUNC(pred_angular_0)(uint8_t *src, const uint8_t *top, + const uint8_t *left, + ptrdiff_t stride, int c_idx, int mode, + int disable_intra_boundary_filter BIT_DEPTH_PARAM) +{ + FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 2, + disable_intra_boundary_filter BIT_DEPTH_ARG); +} + +static void FUNC(pred_angular_1)(uint8_t *src, const uint8_t *top, + const uint8_t *left, + ptrdiff_t stride, int c_idx, int mode, + int disable_intra_boundary_filter BIT_DEPTH_PARAM) +{ + FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 3, + disable_intra_boundary_filter BIT_DEPTH_ARG); +} + +static void FUNC(pred_angular_2)(uint8_t *src, const uint8_t *top, + const uint8_t *left, + ptrdiff_t stride, int c_idx, int mode, + int disable_intra_boundary_filter BIT_DEPTH_PARAM) +{ + FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 4, + disable_intra_boundary_filter BIT_DEPTH_ARG); +} + +static void FUNC(pred_angular_3)(uint8_t *src, const uint8_t *top, + const uint8_t *left, + ptrdiff_t stride, int c_idx, int mode, + int disable_intra_boundary_filter BIT_DEPTH_PARAM) +{ + FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 5, + disable_intra_boundary_filter BIT_DEPTH_ARG); +} +#endif + +#undef EXTEND_LEFT_CIP +#undef EXTEND_RIGHT_CIP +#undef EXTEND_UP_CIP +#undef EXTEND_DOWN_CIP +#undef IS_INTRA +#undef MVF_PU +#undef MVF +#undef PU +#undef EXTEND +#undef MIN_TB_ADDR_ZS +#undef POS diff --git a/libavcodec/internal.h b/libavcodec/internal.h new file mode 100644 index 0000000..dcb2113 --- /dev/null +++ b/libavcodec/internal.h @@ -0,0 +1,267 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal api header. + */ + +#ifndef AVCODEC_INTERNAL_H +#define AVCODEC_INTERNAL_H + +#include + +#include "libavutil/buffer.h" +#include "libavutil/channel_layout.h" +#include "libavutil/mathematics.h" +#include "libavutil/pixfmt.h" +#include "avcodec.h" +#include "config.h" + +#define FF_SANE_NB_CHANNELS 63U + +#if HAVE_AVX +# define STRIDE_ALIGN 32 +#elif HAVE_SIMD_ALIGN_16 +# define STRIDE_ALIGN 16 +#else +# define STRIDE_ALIGN 8 +#endif + +typedef struct FramePool { + /** + * Pools for each data plane. For audio all the planes have the same size, + * so only pools[0] is used. + */ + AVBufferPool *pools[4]; + + /* + * Pool parameters + */ + int format; + int width, height; + int stride_align[AV_NUM_DATA_POINTERS]; + int linesize[4]; + int planes; + int channels; + int samples; +} FramePool; + +typedef struct AVCodecInternal { + /** + * Whether the parent AVCodecContext is a copy of the context which had + * init() called on it. + * This is used by multithreading - shared tables and picture pointers + * should be freed from the original context only. + */ + int is_copy; + + /** + * Whether to allocate progress for frame threading. + * + * The codec must set it to 1 if it uses ff_thread_await/report_progress(), + * then progress will be allocated in ff_thread_get_buffer(). The frames + * then MUST be freed with ff_thread_release_buffer(). + * + * If the codec does not need to call the progress functions (there are no + * dependencies between the frames), it should leave this at 0. Then it can + * decode straight to the user-provided frames (which the user will then + * free with av_frame_unref()), there is no need to call + * ff_thread_release_buffer(). + */ + int allocate_progress; + +#if FF_API_OLD_ENCODE_AUDIO + /** + * Internal sample count used by avcodec_encode_audio() to fabricate pts. + * Can be removed along with avcodec_encode_audio(). + */ + int64_t sample_count; +#endif + + /** + * An audio frame with less than required samples has been submitted and + * padded with silence. Reject all subsequent frames. + */ + int last_audio_frame; + + AVFrame *to_free; + + FramePool *pool; + + void *thread_ctx; + + /** + * Current packet as passed into the decoder, to avoid having to pass the + * packet into every function. + */ + AVPacket *pkt; + + /** + * temporary buffer used for encoders to store their bitstream + */ + uint8_t *byte_buffer; + unsigned int byte_buffer_size; + + void *frame_thread_encoder; + + /** + * Number of audio samples to skip at the start of the next decoded frame + */ + int skip_samples; + + /** + * hwaccel-specific private data + */ + void *hwaccel_priv_data; +} AVCodecInternal; + +struct AVCodecDefault { + const uint8_t *key; + const uint8_t *value; +}; + +extern const uint8_t ff_log2_run[41]; + +/** + * Return the index into tab at which {a,b} match elements {[0],[1]} of tab. + * If there is no such matching pair then size is returned. + */ +int ff_match_2uint16(const uint16_t (*tab)[2], int size, int a, int b); + +unsigned int avpriv_toupper4(unsigned int x); + +/** + * does needed setup of pkt_pts/pos and such for (re)get_buffer(); + */ +int ff_init_buffer_info(AVCodecContext *s, AVFrame *frame); + + +void avpriv_color_frame(AVFrame *frame, const int color[4]); + +extern volatile int ff_avcodec_locked; +int ff_lock_avcodec(AVCodecContext *log_ctx); +int ff_unlock_avcodec(void); + +int avpriv_lock_avformat(void); +int avpriv_unlock_avformat(void); + +/** + * Maximum size in bytes of extradata. + * This value was chosen such that every bit of the buffer is + * addressable by a 32-bit signed integer as used by get_bits. + */ +#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE) + +/** + * Check AVPacket size and/or allocate data. + * + * Encoders supporting AVCodec.encode2() can use this as a convenience to + * ensure the output packet data is large enough, whether provided by the user + * or allocated in this function. + * + * @param avctx the AVCodecContext of the encoder + * @param avpkt the AVPacket + * If avpkt->data is already set, avpkt->size is checked + * to ensure it is large enough. + * If avpkt->data is NULL, a new buffer is allocated. + * avpkt->size is set to the specified size. + * All other AVPacket fields will be reset with av_init_packet(). + * @param size the minimum required packet size + * @return 0 on success, negative error code on failure + */ +int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size); + +int ff_alloc_packet(AVPacket *avpkt, int size); + +/** + * Rescale from sample rate to AVCodecContext.time_base. + */ +static av_always_inline int64_t ff_samples_to_time_base(AVCodecContext *avctx, + int64_t samples) +{ + if(samples == AV_NOPTS_VALUE) + return AV_NOPTS_VALUE; + return av_rescale_q(samples, (AVRational){ 1, avctx->sample_rate }, + avctx->time_base); +} + +/** + * Get a buffer for a frame. This is a wrapper around + * AVCodecContext.get_buffer() and should be used instead calling get_buffer() + * directly. + */ +int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags); + +/** + * Identical in function to av_frame_make_writable(), except it uses + * ff_get_buffer() to allocate the buffer when needed. + */ +int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame); + +int ff_thread_can_start_frame(AVCodecContext *avctx); + +int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx); + +/** + * Call avcodec_open2 recursively by decrementing counter, unlocking mutex, + * calling the function and then restoring again. Assumes the mutex is + * already locked + */ +int ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Finalize buf into extradata and set its size appropriately. + */ +int avpriv_bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf); + +const uint8_t *avpriv_find_start_code(const uint8_t *p, + const uint8_t *end, + uint32_t *state); + +/** + * Check that the provided frame dimensions are valid and set them on the codec + * context. + */ +int ff_set_dimensions(AVCodecContext *s, int width, int height); + +/** + * Check that the provided sample aspect ratio is valid and set it on the codec + * context. + */ +int ff_set_sar(AVCodecContext *avctx, AVRational sar); + +/** + * Add or update AV_FRAME_DATA_MATRIXENCODING side data. + */ +int ff_side_data_update_matrix_encoding(AVFrame *frame, + enum AVMatrixEncoding matrix_encoding); + +/** + * Select the (possibly hardware accelerated) pixel format. + * This is a wrapper around AVCodecContext.get_format() and should be used + * instead of calling get_format() directly. + */ +int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); + +/** + * Set various frame properties from the codec context / packet data. + */ +int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame); + +#endif /* AVCODEC_INTERNAL_H */ diff --git a/libavcodec/mathops.h b/libavcodec/mathops.h new file mode 100644 index 0000000..87fca0c --- /dev/null +++ b/libavcodec/mathops.h @@ -0,0 +1,230 @@ +/* + * simple math operations + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer et al + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVCODEC_MATHOPS_H +#define AVCODEC_MATHOPS_H + +#include + +#include "libavutil/common.h" +#include "config.h" + +#define MAX_NEG_CROP 1024 + +extern const uint32_t ff_inverse[257]; +extern const uint8_t ff_reverse[256]; +extern const uint8_t ff_sqrt_tab[256]; +extern const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +extern const uint8_t ff_zigzag_direct[64]; + +#if ARCH_ARM +# include "arm/mathops.h" +#elif ARCH_AVR32 +# include "avr32/mathops.h" +#elif ARCH_MIPS +# include "mips/mathops.h" +#elif ARCH_PPC +# include "ppc/mathops.h" +#elif ARCH_X86 +# include "x86/mathops.h" +#endif + +/* generic implementation */ + +#ifndef MUL64 +# define MUL64(a,b) ((int64_t)(a) * (int64_t)(b)) +#endif + +#ifndef MULL +# define MULL(a,b,s) (MUL64(a, b) >> (s)) +#endif + +#ifndef MULH +static av_always_inline int MULH(int a, int b){ + return MUL64(a, b) >> 32; +} +#endif + +#ifndef UMULH +static av_always_inline unsigned UMULH(unsigned a, unsigned b){ + return ((uint64_t)(a) * (uint64_t)(b))>>32; +} +#endif + +#ifndef MAC64 +# define MAC64(d, a, b) ((d) += MUL64(a, b)) +#endif + +#ifndef MLS64 +# define MLS64(d, a, b) ((d) -= MUL64(a, b)) +#endif + +/* signed 16x16 -> 32 multiply add accumulate */ +#ifndef MAC16 +# define MAC16(rt, ra, rb) rt += (ra) * (rb) +#endif + +/* signed 16x16 -> 32 multiply */ +#ifndef MUL16 +# define MUL16(ra, rb) ((ra) * (rb)) +#endif + +#ifndef MLS16 +# define MLS16(rt, ra, rb) ((rt) -= (ra) * (rb)) +#endif + +/* median of 3 */ +#ifndef mid_pred +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) +{ +#if 0 + int t= (a-b)&((a-b)>>31); + a-=t; + b+=t; + b-= (b-c)&((b-c)>>31); + b+= (a-b)&((a-b)>>31); + + return b; +#else + if(a>b){ + if(c>b){ + if(c>a) b=a; + else b=c; + } + }else{ + if(b>c){ + if(c>a) b=c; + else b=a; + } + } + return b; +#endif +} +#endif + +#ifndef sign_extend +static inline av_const int sign_extend(int val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned) val << shift }; + return v.s >> shift; +} +#endif + +#ifndef zero_extend +static inline av_const unsigned zero_extend(unsigned val, unsigned bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} +#endif + +#ifndef COPY3_IF_LT +#define COPY3_IF_LT(x, y, a, b, c, d)\ +if ((y) < (x)) {\ + (x) = (y);\ + (a) = (b);\ + (c) = (d);\ +} +#endif + +#ifndef MASK_ABS +#define MASK_ABS(mask, level) do { \ + mask = level >> 31; \ + level = (level ^ mask) - mask; \ + } while (0) +#endif + +#ifndef NEG_SSR32 +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +#endif + +#ifndef NEG_USR32 +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +#if HAVE_BIGENDIAN +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((a) << 8) | (b)) +# endif +# ifndef PACK_4U8 +# define PACK_4U8(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((a) << 16) | (b)) +# endif +#else +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((b) << 8) | (a)) +# endif +# ifndef PACK_4U2 +# define PACK_4U8(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((b) << 16) | (a)) +# endif +#endif + +#ifndef PACK_2S8 +# define PACK_2S8(a,b) PACK_2U8((a)&255, (b)&255) +#endif +#ifndef PACK_4S8 +# define PACK_4S8(a,b,c,d) PACK_4U8((a)&255, (b)&255, (c)&255, (d)&255) +#endif +#ifndef PACK_2S16 +# define PACK_2S16(a,b) PACK_2U16((a)&0xffff, (b)&0xffff) +#endif + +#ifndef FASTDIV +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a) * ff_inverse[b]) >> 32)) +#endif /* FASTDIV */ + +static inline av_const unsigned int ff_sqrt(unsigned int a) +{ + unsigned int b; + + if (a < 255) return (ff_sqrt_tab[a + 1] - 1) >> 4; + else if (a < (1 << 12)) b = ff_sqrt_tab[a >> 4] >> 2; +#if !CONFIG_SMALL + else if (a < (1 << 14)) b = ff_sqrt_tab[a >> 6] >> 1; + else if (a < (1 << 16)) b = ff_sqrt_tab[a >> 8] ; +#endif + else { + int s = av_log2_16bit(a >> 16) >> 1; + unsigned int c = a >> (s + 2); + b = ff_sqrt_tab[c >> (s + 8)]; + b = FASTDIV(c,b) + (b << s); + } + + return b - (a < b * b); +} + +static inline int8_t ff_u8_to_s8(uint8_t a) +{ + union { + uint8_t u8; + int8_t s8; + } b; + b.u8 = a; + return b.s8; +} + +#endif /* AVCODEC_MATHOPS_H */ diff --git a/libavcodec/old_codec_ids.h b/libavcodec/old_codec_ids.h new file mode 100644 index 0000000..c7aa0e0 --- /dev/null +++ b/libavcodec/old_codec_ids.h @@ -0,0 +1,397 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OLD_CODEC_IDS_H +#define AVCODEC_OLD_CODEC_IDS_H + +/* + * This header exists to prevent new codec IDs from being accidentally added to + * the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVCodecID enum instead. + */ + + CODEC_ID_NONE = AV_CODEC_ID_NONE, + + /* video codecs */ + CODEC_ID_MPEG1VIDEO, + CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + CODEC_ID_MPEG2VIDEO_XVMC, +#endif + CODEC_ID_H261, + CODEC_ID_H263, + CODEC_ID_RV10, + CODEC_ID_RV20, + CODEC_ID_MJPEG, + CODEC_ID_MJPEGB, + CODEC_ID_LJPEG, + CODEC_ID_SP5X, + CODEC_ID_JPEGLS, + CODEC_ID_MPEG4, + CODEC_ID_RAWVIDEO, + CODEC_ID_MSMPEG4V1, + CODEC_ID_MSMPEG4V2, + CODEC_ID_MSMPEG4V3, + CODEC_ID_WMV1, + CODEC_ID_WMV2, + CODEC_ID_H263P, + CODEC_ID_H263I, + CODEC_ID_FLV1, + CODEC_ID_SVQ1, + CODEC_ID_SVQ3, + CODEC_ID_DVVIDEO, + CODEC_ID_HUFFYUV, + CODEC_ID_CYUV, + CODEC_ID_H264, + CODEC_ID_INDEO3, + CODEC_ID_VP3, + CODEC_ID_THEORA, + CODEC_ID_ASV1, + CODEC_ID_ASV2, + CODEC_ID_FFV1, + CODEC_ID_4XM, + CODEC_ID_VCR1, + CODEC_ID_CLJR, + CODEC_ID_MDEC, + CODEC_ID_ROQ, + CODEC_ID_INTERPLAY_VIDEO, + CODEC_ID_XAN_WC3, + CODEC_ID_XAN_WC4, + CODEC_ID_RPZA, + CODEC_ID_CINEPAK, + CODEC_ID_WS_VQA, + CODEC_ID_MSRLE, + CODEC_ID_MSVIDEO1, + CODEC_ID_IDCIN, + CODEC_ID_8BPS, + CODEC_ID_SMC, + CODEC_ID_FLIC, + CODEC_ID_TRUEMOTION1, + CODEC_ID_VMDVIDEO, + CODEC_ID_MSZH, + CODEC_ID_ZLIB, + CODEC_ID_QTRLE, + CODEC_ID_TSCC, + CODEC_ID_ULTI, + CODEC_ID_QDRAW, + CODEC_ID_VIXL, + CODEC_ID_QPEG, + CODEC_ID_PNG, + CODEC_ID_PPM, + CODEC_ID_PBM, + CODEC_ID_PGM, + CODEC_ID_PGMYUV, + CODEC_ID_PAM, + CODEC_ID_FFVHUFF, + CODEC_ID_RV30, + CODEC_ID_RV40, + CODEC_ID_VC1, + CODEC_ID_WMV3, + CODEC_ID_LOCO, + CODEC_ID_WNV1, + CODEC_ID_AASC, + CODEC_ID_INDEO2, + CODEC_ID_FRAPS, + CODEC_ID_TRUEMOTION2, + CODEC_ID_BMP, + CODEC_ID_CSCD, + CODEC_ID_MMVIDEO, + CODEC_ID_ZMBV, + CODEC_ID_AVS, + CODEC_ID_SMACKVIDEO, + CODEC_ID_NUV, + CODEC_ID_KMVC, + CODEC_ID_FLASHSV, + CODEC_ID_CAVS, + CODEC_ID_JPEG2000, + CODEC_ID_VMNC, + CODEC_ID_VP5, + CODEC_ID_VP6, + CODEC_ID_VP6F, + CODEC_ID_TARGA, + CODEC_ID_DSICINVIDEO, + CODEC_ID_TIERTEXSEQVIDEO, + CODEC_ID_TIFF, + CODEC_ID_GIF, + CODEC_ID_DXA, + CODEC_ID_DNXHD, + CODEC_ID_THP, + CODEC_ID_SGI, + CODEC_ID_C93, + CODEC_ID_BETHSOFTVID, + CODEC_ID_PTX, + CODEC_ID_TXD, + CODEC_ID_VP6A, + CODEC_ID_AMV, + CODEC_ID_VB, + CODEC_ID_PCX, + CODEC_ID_SUNRAST, + CODEC_ID_INDEO4, + CODEC_ID_INDEO5, + CODEC_ID_MIMIC, + CODEC_ID_RL2, + CODEC_ID_ESCAPE124, + CODEC_ID_DIRAC, + CODEC_ID_BFI, + CODEC_ID_CMV, + CODEC_ID_MOTIONPIXELS, + CODEC_ID_TGV, + CODEC_ID_TGQ, + CODEC_ID_TQI, + CODEC_ID_AURA, + CODEC_ID_AURA2, + CODEC_ID_V210X, + CODEC_ID_TMV, + CODEC_ID_V210, + CODEC_ID_DPX, + CODEC_ID_MAD, + CODEC_ID_FRWU, + CODEC_ID_FLASHSV2, + CODEC_ID_CDGRAPHICS, + CODEC_ID_R210, + CODEC_ID_ANM, + CODEC_ID_BINKVIDEO, + CODEC_ID_IFF_ILBM, + CODEC_ID_IFF_BYTERUN1, + CODEC_ID_KGV1, + CODEC_ID_YOP, + CODEC_ID_VP8, + CODEC_ID_PICTOR, + CODEC_ID_ANSI, + CODEC_ID_A64_MULTI, + CODEC_ID_A64_MULTI5, + CODEC_ID_R10K, + CODEC_ID_MXPEG, + CODEC_ID_LAGARITH, + CODEC_ID_PRORES, + CODEC_ID_JV, + CODEC_ID_DFA, + CODEC_ID_WMV3IMAGE, + CODEC_ID_VC1IMAGE, + CODEC_ID_UTVIDEO, + CODEC_ID_BMV_VIDEO, + CODEC_ID_VBLE, + CODEC_ID_DXTORY, + CODEC_ID_V410, + CODEC_ID_XWD, + CODEC_ID_CDXL, + CODEC_ID_XBM, + CODEC_ID_ZEROCODEC, + CODEC_ID_MSS1, + CODEC_ID_MSA1, + CODEC_ID_TSCC2, + CODEC_ID_MTS2, + CODEC_ID_CLLC, + CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), + CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), + CODEC_ID_EXR = MKBETAG('0','E','X','R'), + CODEC_ID_AVRP = MKBETAG('A','V','R','P'), + + CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'), + CODEC_ID_AVUI = MKBETAG('A','V','U','I'), + CODEC_ID_AYUV = MKBETAG('A','Y','U','V'), + CODEC_ID_V308 = MKBETAG('V','3','0','8'), + CODEC_ID_V408 = MKBETAG('V','4','0','8'), + CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'), + CODEC_ID_SANM = MKBETAG('S','A','N','M'), + CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'), + CODEC_ID_SNOW = AV_CODEC_ID_SNOW, + + /* various PCM "codecs" */ + CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + CODEC_ID_PCM_S16LE = 0x10000, + CODEC_ID_PCM_S16BE, + CODEC_ID_PCM_U16LE, + CODEC_ID_PCM_U16BE, + CODEC_ID_PCM_S8, + CODEC_ID_PCM_U8, + CODEC_ID_PCM_MULAW, + CODEC_ID_PCM_ALAW, + CODEC_ID_PCM_S32LE, + CODEC_ID_PCM_S32BE, + CODEC_ID_PCM_U32LE, + CODEC_ID_PCM_U32BE, + CODEC_ID_PCM_S24LE, + CODEC_ID_PCM_S24BE, + CODEC_ID_PCM_U24LE, + CODEC_ID_PCM_U24BE, + CODEC_ID_PCM_S24DAUD, + CODEC_ID_PCM_ZORK, + CODEC_ID_PCM_S16LE_PLANAR, + CODEC_ID_PCM_DVD, + CODEC_ID_PCM_F32BE, + CODEC_ID_PCM_F32LE, + CODEC_ID_PCM_F64BE, + CODEC_ID_PCM_F64LE, + CODEC_ID_PCM_BLURAY, + CODEC_ID_PCM_LXF, + CODEC_ID_S302M, + CODEC_ID_PCM_S8_PLANAR, + + /* various ADPCM codecs */ + CODEC_ID_ADPCM_IMA_QT = 0x11000, + CODEC_ID_ADPCM_IMA_WAV, + CODEC_ID_ADPCM_IMA_DK3, + CODEC_ID_ADPCM_IMA_DK4, + CODEC_ID_ADPCM_IMA_WS, + CODEC_ID_ADPCM_IMA_SMJPEG, + CODEC_ID_ADPCM_MS, + CODEC_ID_ADPCM_4XM, + CODEC_ID_ADPCM_XA, + CODEC_ID_ADPCM_ADX, + CODEC_ID_ADPCM_EA, + CODEC_ID_ADPCM_G726, + CODEC_ID_ADPCM_CT, + CODEC_ID_ADPCM_SWF, + CODEC_ID_ADPCM_YAMAHA, + CODEC_ID_ADPCM_SBPRO_4, + CODEC_ID_ADPCM_SBPRO_3, + CODEC_ID_ADPCM_SBPRO_2, + CODEC_ID_ADPCM_THP, + CODEC_ID_ADPCM_IMA_AMV, + CODEC_ID_ADPCM_EA_R1, + CODEC_ID_ADPCM_EA_R3, + CODEC_ID_ADPCM_EA_R2, + CODEC_ID_ADPCM_IMA_EA_SEAD, + CODEC_ID_ADPCM_IMA_EA_EACS, + CODEC_ID_ADPCM_EA_XAS, + CODEC_ID_ADPCM_EA_MAXIS_XA, + CODEC_ID_ADPCM_IMA_ISS, + CODEC_ID_ADPCM_G722, + CODEC_ID_ADPCM_IMA_APC, + CODEC_ID_VIMA = MKBETAG('V','I','M','A'), + + /* AMR */ + CODEC_ID_AMR_NB = 0x12000, + CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + CODEC_ID_RA_144 = 0x13000, + CODEC_ID_RA_288, + + /* various DPCM codecs */ + CODEC_ID_ROQ_DPCM = 0x14000, + CODEC_ID_INTERPLAY_DPCM, + CODEC_ID_XAN_DPCM, + CODEC_ID_SOL_DPCM, + + /* audio codecs */ + CODEC_ID_MP2 = 0x15000, + CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + CODEC_ID_AAC, + CODEC_ID_AC3, + CODEC_ID_DTS, + CODEC_ID_VORBIS, + CODEC_ID_DVAUDIO, + CODEC_ID_WMAV1, + CODEC_ID_WMAV2, + CODEC_ID_MACE3, + CODEC_ID_MACE6, + CODEC_ID_VMDAUDIO, + CODEC_ID_FLAC, + CODEC_ID_MP3ADU, + CODEC_ID_MP3ON4, + CODEC_ID_SHORTEN, + CODEC_ID_ALAC, + CODEC_ID_WESTWOOD_SND1, + CODEC_ID_GSM, ///< as in Berlin toast format + CODEC_ID_QDM2, + CODEC_ID_COOK, + CODEC_ID_TRUESPEECH, + CODEC_ID_TTA, + CODEC_ID_SMACKAUDIO, + CODEC_ID_QCELP, + CODEC_ID_WAVPACK, + CODEC_ID_DSICINAUDIO, + CODEC_ID_IMC, + CODEC_ID_MUSEPACK7, + CODEC_ID_MLP, + CODEC_ID_GSM_MS, /* as found in WAV */ + CODEC_ID_ATRAC3, + CODEC_ID_VOXWARE, + CODEC_ID_APE, + CODEC_ID_NELLYMOSER, + CODEC_ID_MUSEPACK8, + CODEC_ID_SPEEX, + CODEC_ID_WMAVOICE, + CODEC_ID_WMAPRO, + CODEC_ID_WMALOSSLESS, + CODEC_ID_ATRAC3P, + CODEC_ID_EAC3, + CODEC_ID_SIPR, + CODEC_ID_MP1, + CODEC_ID_TWINVQ, + CODEC_ID_TRUEHD, + CODEC_ID_MP4ALS, + CODEC_ID_ATRAC1, + CODEC_ID_BINKAUDIO_RDFT, + CODEC_ID_BINKAUDIO_DCT, + CODEC_ID_AAC_LATM, + CODEC_ID_QDMC, + CODEC_ID_CELT, + CODEC_ID_G723_1, + CODEC_ID_G729, + CODEC_ID_8SVX_EXP, + CODEC_ID_8SVX_FIB, + CODEC_ID_BMV_AUDIO, + CODEC_ID_RALF, + CODEC_ID_IAC, + CODEC_ID_ILBC, + CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'), + CODEC_ID_SONIC = MKBETAG('S','O','N','C'), + CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'), + CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'), + CODEC_ID_OPUS = MKBETAG('O','P','U','S'), + + /* subtitle codecs */ + CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + CODEC_ID_DVD_SUBTITLE = 0x17000, + CODEC_ID_DVB_SUBTITLE, + CODEC_ID_TEXT, ///< raw UTF-8 text + CODEC_ID_XSUB, + CODEC_ID_SSA, + CODEC_ID_MOV_TEXT, + CODEC_ID_HDMV_PGS_SUBTITLE, + CODEC_ID_DVB_TELETEXT, + CODEC_ID_SRT, + CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'), + CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'), + CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'), + CODEC_ID_SAMI = MKBETAG('S','A','M','I'), + CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'), + CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'), + + /* other specific kind of codecs (generally used for attachments) */ + CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + CODEC_ID_TTF = 0x18000, + CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), + CODEC_ID_XBIN = MKBETAG('X','B','I','N'), + CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), + CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), + + CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it + + CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + +#endif /* AVCODEC_OLD_CODEC_IDS_H */ diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h new file mode 100644 index 0000000..8858caa --- /dev/null +++ b/libavcodec/put_bits.h @@ -0,0 +1,258 @@ +/* + * copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream writer API + */ + +#ifndef AVCODEC_PUT_BITS_H +#define AVCODEC_PUT_BITS_H + +#include +#include +#include + +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" + +typedef struct PutBitContext { + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; + int size_in_bits; +} PutBitContext; + +/** + * Initialize the PutBitContext s. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer + */ +static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + if (buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->size_in_bits = 8 * buffer_size; + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + s->buf_ptr = s->buf; + s->bit_left = 32; + s->bit_buf = 0; +} + +/** + * Rebase the bit writer onto a reallocated buffer. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer, + * must be larger than the previous size + */ +static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + av_assert0(8*buffer_size > s->size_in_bits); + + s->buf_end = buffer + buffer_size; + s->buf_ptr = buffer + (s->buf_ptr - s->buf); + s->buf = buffer; + s->size_in_bits = 8 * buffer_size; +} + +/** + * @return the total number of bits written to the bitstream. + */ +static inline int put_bits_count(PutBitContext *s) +{ + return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left; +} + +/** + * @return the number of bits available in the bitstream. + */ +static inline int put_bits_left(PutBitContext* s) +{ + return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left; +} + +/** + * Pad the end of the output stream with zeros. + */ +static inline void flush_put_bits(PutBitContext *s) +{ +#ifndef BITSTREAM_WRITER_LE + if (s->bit_left < 32) + s->bit_buf <<= s->bit_left; +#endif + while (s->bit_left < 32) { + /* XXX: should test end of buffer */ +#ifdef BITSTREAM_WRITER_LE + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; +#else + *s->buf_ptr++ = s->bit_buf >> 24; + s->bit_buf <<= 8; +#endif + s->bit_left += 8; + } + s->bit_left = 32; + s->bit_buf = 0; +} + +#ifdef BITSTREAM_WRITER_LE +#define avpriv_align_put_bits align_put_bits_unsupported_here +#define avpriv_put_string ff_put_string_unsupported_here +#define avpriv_copy_bits avpriv_copy_bits_unsupported_here +#else +/** + * Pad the bitstream with zeros up to the next byte boundary. + */ +void avpriv_align_put_bits(PutBitContext *s); + +/** + * Put the string string in the bitstream. + * + * @param terminate_string 0-terminates the written string if value is 1 + */ +void avpriv_put_string(PutBitContext *pb, const char *string, + int terminate_string); + +/** + * Copy the content of src to the bitstream. + * + * @param length the number of bits of src to copy + */ +void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length); +#endif + +/** + * Write up to 31 bits into a bitstream. + * Use put_bits32 to write 32 bits. + */ +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + + av_assert2(n <= 31 && value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + /* XXX: optimize */ +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + av_assert2(s->buf_ptr+3buf_end); + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + bit_buf = (bit_left == 32) ? 0 : value >> bit_left; + bit_left += 32; + } + bit_left -= n; +#else + if (n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + av_assert2(s->buf_ptr+3buf_end); + AV_WB32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + bit_left += 32 - n; + bit_buf = value; + } +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_sbits(PutBitContext *pb, int n, int32_t value) +{ + av_assert2(n >= 0 && n <= 31); + + put_bits(pb, n, value & ((1 << n) - 1)); +} + +/** + * Write exactly 32 bits into a bitstream. + */ +static void av_unused put_bits32(PutBitContext *s, uint32_t value) +{ + int lo = value & 0xffff; + int hi = value >> 16; +#ifdef BITSTREAM_WRITER_LE + put_bits(s, 16, lo); + put_bits(s, 16, hi); +#else + put_bits(s, 16, hi); + put_bits(s, 16, lo); +#endif +} + +/** + * Return the pointer to the byte where the bitstream writer will put + * the next bit. + */ +static inline uint8_t *put_bits_ptr(PutBitContext *s) +{ + return s->buf_ptr; +} + +/** + * Skip the given number of bytes. + * PutBitContext must be flushed & aligned to a byte boundary before calling this. + */ +static inline void skip_put_bytes(PutBitContext *s, int n) +{ + av_assert2((put_bits_count(s) & 7) == 0); + av_assert2(s->bit_left == 32); + s->buf_ptr += n; +} + +/** + * Skip the given number of bits. + * Must only be used if the actual values in the bitstream do not matter. + * If n is 0 the behavior is undefined. + */ +static inline void skip_put_bits(PutBitContext *s, int n) +{ + s->bit_left -= n; + s->buf_ptr -= 4 * (s->bit_left >> 5); + s->bit_left &= 31; +} + +/** + * Change the end of the buffer. + * + * @param size the new size in bytes of the buffer where to put bits + */ +static inline void set_put_bits_buffer_size(PutBitContext *s, int size) +{ + s->buf_end = s->buf + size; +} + +#endif /* AVCODEC_PUT_BITS_H */ diff --git a/libavcodec/rnd_avg.h b/libavcodec/rnd_avg.h new file mode 100644 index 0000000..344775e --- /dev/null +++ b/libavcodec/rnd_avg.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2001-2003 BERO + * Copyright (c) 2011 Oskar Arvidsson + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RND_AVG_H +#define AVCODEC_RND_AVG_H + +#include +#include + +#define BYTE_VEC32(c) ((c) * 0x01010101UL) +#define BYTE_VEC64(c) ((c) * 0x0001000100010001UL) + +static inline uint32_t rnd_avg32(uint32_t a, uint32_t b) +{ + return (a | b) - (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1); +} + +static inline uint32_t no_rnd_avg32(uint32_t a, uint32_t b) +{ + return (a & b) + (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1); +} + +static inline uint64_t rnd_avg64(uint64_t a, uint64_t b) +{ + return (a | b) - (((a ^ b) & ~BYTE_VEC64(0x01)) >> 1); +} + +static inline uint64_t no_rnd_avg64(uint64_t a, uint64_t b) +{ + return (a & b) + (((a ^ b) & ~BYTE_VEC64(0x01)) >> 1); +} + +#endif /* AVCODEC_RND_AVG_H */ diff --git a/libavcodec/thread.h b/libavcodec/thread.h new file mode 100644 index 0000000..c848d7a --- /dev/null +++ b/libavcodec/thread.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2008 Alexander Strange + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Multithreading support functions + * @author Alexander Strange + */ + +#ifndef AVCODEC_THREAD_H +#define AVCODEC_THREAD_H + +#include "libavutil/buffer.h" + +#include "config.h" +#include "avcodec.h" + +typedef struct ThreadFrame { + AVFrame *f; + AVCodecContext *owner; + // progress->data is an array of 2 ints holding progress for top/bottom + // fields + AVBufferRef *progress; +} ThreadFrame; + +/** + * Wait for decoding threads to finish and reset internal state. + * Called by avcodec_flush_buffers(). + * + * @param avctx The context. + */ +void ff_thread_flush(AVCodecContext *avctx); + +/** + * Submit a new frame to a decoding thread. + * Returns the next available frame in picture. *got_picture_ptr + * will be 0 if none is available. + * The return value on success is the size of the consumed packet for + * compatibility with avcodec_decode_video2(). This means the decoder + * has to consume the full packet. + * + * Parameters are the same as avcodec_decode_video2(). + */ +int ff_thread_decode_frame(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, AVPacket *avpkt); + +/** + * If the codec defines update_thread_context(), call this + * when they are ready for the next thread to start decoding + * the next frame. After calling it, do not change any variables + * read by the update_thread_context() method, or call ff_thread_get_buffer(). + * + * @param avctx The context. + */ +void ff_thread_finish_setup(AVCodecContext *avctx); + +/** + * Notify later decoding threads when part of their reference picture is ready. + * Call this when some part of the picture is finished decoding. + * Later calls with lower values of progress have no effect. + * + * @param f The picture being decoded. + * @param progress Value, in arbitrary units, of how much of the picture has decoded. + * @param field The field being decoded, for field-picture codecs. + * 0 for top field or frame pictures, 1 for bottom field. + */ +void ff_thread_report_progress(ThreadFrame *f, int progress, int field); + +/** + * Wait for earlier decoding threads to finish reference pictures. + * Call this before accessing some part of a picture, with a given + * value for progress, and it will return after the responsible decoding + * thread calls ff_thread_report_progress() with the same or + * higher value for progress. + * + * @param f The picture being referenced. + * @param progress Value, in arbitrary units, to wait for. + * @param field The field being referenced, for field-picture codecs. + * 0 for top field or frame pictures, 1 for bottom field. + */ +void ff_thread_await_progress(ThreadFrame *f, int progress, int field); + +/** + * Wrapper around get_format() for frame-multithreaded codecs. + * Call this function instead of avctx->get_format(). + * Cannot be called after the codec has called ff_thread_finish_setup(). + * + * @param avctx The current context. + * @param fmt The list of available formats. + */ +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); + +/** + * Wrapper around get_buffer() for frame-multithreaded codecs. + * Call this function instead of ff_get_buffer(f). + * Cannot be called after the codec has called ff_thread_finish_setup(). + * + * @param avctx The current context. + * @param f The frame to write into. + */ +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags); + +/** + * Wrapper around release_buffer() frame-for multithreaded codecs. + * Call this function instead of avctx->release_buffer(f). + * The AVFrame will be copied and the actual release_buffer() call + * will be performed later. The contents of data pointed to by the + * AVFrame should not be changed until ff_thread_get_buffer() is called + * on it. + * + * @param avctx The current context. + * @param f The picture being released. + */ +void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f); + +int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src); + +int ff_thread_init(AVCodecContext *s); +void ff_thread_free(AVCodecContext *s); + +int ff_alloc_entries(AVCodecContext *avctx, int count); +void ff_reset_entries(AVCodecContext *avctx); +void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n); +void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift); + +#endif /* AVCODEC_THREAD_H */ diff --git a/libavcodec/utils.c b/libavcodec/utils.c new file mode 100644 index 0000000..83a65d2 --- /dev/null +++ b/libavcodec/utils.c @@ -0,0 +1,369 @@ +/* + * utils for libavcodec + * Copyright (c) 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * utils. + */ + +#include "config.h" +#include "libavutil/atomic.h" +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" +#include "libavutil/channel_layout.h" +#include "libavutil/crc.h" +#include "libavutil/frame.h" +#include "libavutil/internal.h" +#include "libavutil/mathematics.h" +#include "libavutil/pixdesc.h" +#include "libavutil/imgutils.h" +#include "libavutil/samplefmt.h" +#include "libavutil/dict.h" +#include "avcodec.h" +#include "libavutil/opt.h" +#include "thread.h" +#include "internal.h" +#include "bytestream.h" +#include "version.h" +#include +#include +#include +#include +#if CONFIG_ICONV +# include +#endif + +void avcodec_register_all(void) +{ +} + +int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) +{ + int ret = 0; + + if (codec->priv_data_size > 0) { + if (!avctx->priv_data) { + avctx->priv_data = av_mallocz(codec->priv_data_size); + if (!avctx->priv_data) { + ret = AVERROR(ENOMEM); + goto end; + } + } + } else { + avctx->priv_data = NULL; + } + avctx->codec = codec; + avctx->frame_number = 0; + // avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id); + + avctx->thread_count = 1; + + avctx->pts_correction_num_faulty_pts = + avctx->pts_correction_num_faulty_dts = 0; + avctx->pts_correction_last_pts = + avctx->pts_correction_last_dts = INT64_MIN; + + ret = avctx->codec->init(avctx); + if (ret < 0) { + goto free_and_end; + } + + return 0; +free_and_end: + av_freep(&avctx->priv_data); + avctx->codec = NULL; + end: + return ret; +} + +av_cold int avcodec_close(AVCodecContext *avctx) +{ + if (!avctx) + return 0; + + if (avctx->codec && avctx->codec->close) + avctx->codec->close(avctx); + avctx->coded_frame = NULL; + + av_freep(&avctx->priv_data); + avctx->codec = NULL; + avctx->active_thread_type = 0; + + return 0; +} + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size) +{ + int i; + + for (i = 0; i < count; i++) { + int r = func(c, (char *)arg + i * size); + if (ret) + ret[i] = r; + } + return 0; +} + +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int jobnr, int threadnr), void *arg, int *ret, int count) +{ + int i; + + for (i = 0; i < count; i++) { + int r = func(c, arg, i, 0); + if (ret) + ret[i] = r; + } + return 0; +} + +int avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int i, h, linesize, bpp; + + for (i = 0; i < desc->nb_components; i++) { + bpp = (desc->comp[i].depth_minus1 + 8) >> 3; + linesize = FFALIGN(frame->width * bpp, 32); + if (i == 1 || i == 2) + linesize = FF_CEIL_RSHIFT(linesize, desc->log2_chroma_w); + + frame->linesize[i] = linesize; + + h = FFALIGN(frame->height, 32); + if (i == 1 || i == 2) + h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h); + + frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h + 32); + if (!frame->buf[i]) + goto fail; + + frame->data[i] = frame->buf[i]->data; + } + return 0; + fail: + return -1; +} + +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec) +{ + memset(s, 0, sizeof(AVCodecContext)); + + s->codec_type = codec ? codec->type : AVMEDIA_TYPE_UNKNOWN; + if (codec) + s->codec_id = codec->id; + + s->time_base = (AVRational){0,1}; + s->framerate = (AVRational){ 0, 1 }; + s->pkt_timebase = (AVRational){ 0, 1 }; + s->get_buffer2 = avcodec_default_get_buffer2; + // s->get_format = avcodec_default_get_format; + s->execute = avcodec_default_execute; + s->execute2 = avcodec_default_execute2; + s->sample_aspect_ratio = (AVRational){0,1}; + s->pix_fmt = AV_PIX_FMT_NONE; + s->sample_fmt = AV_SAMPLE_FMT_NONE; + + s->reordered_opaque = AV_NOPTS_VALUE; + if(codec && codec->priv_data_size){ + if(!s->priv_data){ + s->priv_data= av_mallocz(codec->priv_data_size); + if (!s->priv_data) { + return AVERROR(ENOMEM); + } + } + } + return 0; +} + +int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src) +{ + return 0; +} + +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) +{ + AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext)); + + if (!avctx) + return NULL; + + if(avcodec_get_context_defaults3(avctx, codec) < 0){ + av_free(avctx); + return NULL; + } + + return avctx; +} + +int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt) +{ + int ret; + // copy to ensure we do not change avpkt + AVPacket tmp = *avpkt; + + if (!avctx->codec) + return AVERROR(EINVAL); + if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) { + av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n"); + return AVERROR(EINVAL); + } + + *got_picture_ptr = 0; + if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx)) + return AVERROR(EINVAL); + + av_frame_unref(picture); + + if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) { + + ret = avctx->codec->decode(avctx, picture, got_picture_ptr, + &tmp); + + if (*got_picture_ptr) { + avctx->frame_number++; + } else { + av_frame_unref(picture); + } + } else { + ret = 0; + } + + /* many decoders assign whole AVFrames, thus overwriting extended_data; + * make sure it's set correctly */ + // av_assert0(!picture->extended_data || picture->extended_data == picture->data); + + return ret; +} + +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +{ + if ((int)w>0 && (int)h>0 && (w+128) < (INT_MAX/8) / (h + 128)) + return 0; + else + return AVERROR(EINVAL); +} + +int ff_set_sar(AVCodecContext *avctx, AVRational sar) +{ + return 0; +} + +static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + int override_dimensions = 1; + int ret; + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0 || avctx->pix_fmt<0) { + av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n"); + return AVERROR(EINVAL); + } + } + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + if (frame->width <= 0 || frame->height <= 0) { + frame->width = FFMAX(avctx->width, FF_CEIL_RSHIFT(avctx->coded_width, avctx->lowres)); + frame->height = FFMAX(avctx->height, FF_CEIL_RSHIFT(avctx->coded_height, avctx->lowres)); + override_dimensions = 0; + } + frame->format = avctx->pix_fmt; + } + ret = avctx->get_buffer2(avctx, frame, flags); + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions) { + frame->width = avctx->width; + frame->height = avctx->height; + } + + return ret; +} + +int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + int ret = get_buffer_internal(avctx, frame, flags); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; +} + +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) +{ + f->owner = avctx; + return ff_get_buffer(avctx, f->f, flags); +} + +void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) +{ + if (f->f) + av_frame_unref(f->f); +} + +void ff_thread_finish_setup(AVCodecContext *avctx) +{ +} + +void ff_thread_report_progress(ThreadFrame *f, int progress, int field) +{ +} + +void ff_thread_await_progress(ThreadFrame *f, int progress, int field) +{ +} + +int ff_thread_can_start_frame(AVCodecContext *avctx) +{ + return 1; +} + +int ff_alloc_entries(AVCodecContext *avctx, int count) +{ + return 0; +} + +void ff_reset_entries(AVCodecContext *avctx) +{ +} + +void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) +{ +} + +void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) +{ +} + +void av_init_packet(AVPacket *pkt) +{ + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; + pkt->duration = 0; + pkt->convergence_duration = 0; + pkt->flags = 0; + pkt->stream_index = 0; + pkt->buf = NULL; + pkt->side_data = NULL; + pkt->side_data_elems = 0; +} diff --git a/libavcodec/version.h b/libavcodec/version.h new file mode 100644 index 0000000..ce4af6c --- /dev/null +++ b/libavcodec/version.h @@ -0,0 +1,188 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 56 +#define LIBAVCODEC_VERSION_MINOR 12 +#define LIBAVCODEC_VERSION_MICRO 101 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_REQUEST_CHANNELS +#define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_DECODE_AUDIO +#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_AUDIO +#define FF_API_OLD_ENCODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_VIDEO +#define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_ID +#define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AUDIO_CONVERT +#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AVCODEC_RESAMPLE +#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT +#endif +#ifndef FF_API_DEINTERLACE +#define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DESTRUCT_PACKET +#define FF_API_DESTRUCT_PACKET (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GET_BUFFER +#define FF_API_GET_BUFFER (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MISSING_SAMPLE +#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CAP_VDPAU +#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_BUFS_VDPAU +#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VOXWARE +#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_SET_DIMENSIONS +#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AC_VLC +#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_MSMPEG4 +#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ASPECT_EXTENDED +#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_THREAD_OPAQUE +#define FF_API_THREAD_OPAQUE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_PKT +#define FF_API_CODEC_PKT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_ALPHA +#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ERROR_RATE +#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_QSCALE_TYPE +#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MB_TYPE +#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MAX_BFRAMES +#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_NEG_LINESIZES +#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_EMU_EDGE +#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_SH4 +#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_SPARC +#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_UNUSED_MEMBERS +#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_IDCT_XVIDMMX +#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_INPUT_PRESERVED +#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_NORMALIZE_AQP +#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GMC +#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MV0 +#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_NAME +#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AFD +#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DV_FRAME_PROFILE +#define FF_API_DV_FRAME_PROFILE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AUDIOENC_DELAY +#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCTX_TIMEBASE +#define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MPV_OPT +#define FF_API_MPV_OPT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif + +#endif /* AVCODEC_VERSION_H */ diff --git a/libavcodec/videodsp.h b/libavcodec/videodsp.h new file mode 100644 index 0000000..fc01a31 --- /dev/null +++ b/libavcodec/videodsp.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Core video DSP helper functions + */ + +#ifndef AVCODEC_VIDEODSP_H +#define AVCODEC_VIDEODSP_H + +#include +#include + +#define EMULATED_EDGE(depth) \ +void ff_emulated_edge_mc_ ## depth(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t dst_stride, ptrdiff_t src_stride, \ + int block_w, int block_h,\ + int src_x, int src_y, int w, int h); + +EMULATED_EDGE(8) +EMULATED_EDGE(16) + +typedef struct VideoDSPContext { + /** + * Copy a rectangular area of samples to a temporary buffer and replicate + * the border samples. + * + * @param dst destination buffer + * @param dst_stride number of bytes between 2 vertically adjacent samples + * in destination buffer + * @param src source buffer + * @param dst_linesize number of bytes between 2 vertically adjacent + * samples in the destination buffer + * @param src_linesize number of bytes between 2 vertically adjacent + * samples in both the source buffer + * @param block_w width of block + * @param block_h height of block + * @param src_x x coordinate of the top left sample of the block in the + * source buffer + * @param src_y y coordinate of the top left sample of the block in the + * source buffer + * @param w width of the source buffer + * @param h height of the source buffer + */ + void (*emulated_edge_mc)(uint8_t *dst, const uint8_t *src, + ptrdiff_t dst_linesize, + ptrdiff_t src_linesize, + int block_w, int block_h, + int src_x, int src_y, int w, int h); + + /** + * Prefetch memory into cache (if supported by hardware). + * + * @param buf pointer to buffer to prefetch memory from + * @param stride distance between two lines of buf (in bytes) + * @param h number of lines to prefetch + */ + void (*prefetch)(uint8_t *buf, ptrdiff_t stride, int h); +} VideoDSPContext; + +void ff_videodsp_init(VideoDSPContext *ctx, int bpc); + +/* for internal use only (i.e. called by ff_videodsp_init() */ +void ff_videodsp_init_aarch64(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_arm(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_ppc(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc); + +#endif /* AVCODEC_VIDEODSP_H */ diff --git a/libavutil/adler32.h b/libavutil/adler32.h new file mode 100644 index 0000000..0dc69ec --- /dev/null +++ b/libavutil/adler32.h @@ -0,0 +1,55 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @file + * Public header for libavutil Adler32 hasher + * + * @defgroup lavu_adler32 Adler32 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/libavutil/aes.h b/libavutil/aes.h new file mode 100644 index 0000000..09efbda --- /dev/null +++ b/libavutil/aes.h @@ -0,0 +1,65 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/libavutil/atomic.h b/libavutil/atomic.h new file mode 100644 index 0000000..15906d2 --- /dev/null +++ b/libavutil/atomic.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATOMIC_H +#define AVUTIL_ATOMIC_H + +#include "config.h" + +#if HAVE_ATOMICS_NATIVE + +#if HAVE_ATOMICS_GCC +#include "atomic_gcc.h" +#elif HAVE_ATOMICS_WIN32 +#include "atomic_win32.h" +#elif HAVE_ATOMICS_SUNCC +#include "atomic_suncc.h" +#endif + +#else + +/** + * Load the current value stored in an atomic integer. + * + * @param ptr atomic integer + * @return the current value of the atomic integer + * @note This acts as a memory barrier. + */ +int avpriv_atomic_int_get(volatile int *ptr); + +/** + * Store a new value in an atomic integer. + * + * @param ptr atomic integer + * @param val the value to store in the atomic integer + * @note This acts as a memory barrier. + */ +void avpriv_atomic_int_set(volatile int *ptr, int val); + +/** + * Add a value to an atomic integer. + * + * @param ptr atomic integer + * @param inc the value to add to the atomic integer (may be negative) + * @return the new value of the atomic integer. + * @note This does NOT act as a memory barrier. This is primarily + * intended for reference counting. + */ +int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc); + +/** + * Atomic pointer compare and swap. + * + * @param ptr pointer to the pointer to operate on + * @param oldval do the swap if the current value of *ptr equals to oldval + * @param newval value to replace *ptr with + * @return the value of *ptr before comparison + */ +void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval); + +#endif /* HAVE_ATOMICS_NATIVE */ + +#endif /* AVUTIL_ATOMIC_H */ diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h new file mode 100644 index 0000000..5f9fc49 --- /dev/null +++ b/libavutil/atomic_gcc.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATOMIC_GCC_H +#define AVUTIL_ATOMIC_GCC_H + +#include + +#include "atomic.h" + +#define avpriv_atomic_int_get atomic_int_get_gcc +static inline int atomic_int_get_gcc(volatile int *ptr) +{ +#if HAVE_ATOMIC_COMPARE_EXCHANGE + return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); +#else + __sync_synchronize(); + return *ptr; +#endif +} + +#define avpriv_atomic_int_set atomic_int_set_gcc +static inline void atomic_int_set_gcc(volatile int *ptr, int val) +{ +#if HAVE_ATOMIC_COMPARE_EXCHANGE + __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST); +#else + *ptr = val; + __sync_synchronize(); +#endif +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_gcc +static inline int atomic_int_add_and_fetch_gcc(volatile int *ptr, int inc) +{ +#if HAVE_ATOMIC_COMPARE_EXCHANGE + return __atomic_add_fetch(ptr, inc, __ATOMIC_SEQ_CST); +#else + return __sync_add_and_fetch(ptr, inc); +#endif +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc +static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, + void *oldval, void *newval) +{ +#if HAVE_SYNC_VAL_COMPARE_AND_SWAP +#ifdef __ARMCC_VERSION + // armcc will throw an error if ptr is not an integer type + volatile uintptr_t *tmp = (volatile uintptr_t*)ptr; + return (void*)__sync_val_compare_and_swap(tmp, oldval, newval); +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +#else + __atomic_compare_exchange_n(ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return oldval; +#endif +} + +#endif /* AVUTIL_ATOMIC_GCC_H */ diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h new file mode 100644 index 0000000..3cad24a --- /dev/null +++ b/libavutil/atomic_suncc.h @@ -0,0 +1,55 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATOMIC_SUNCC_H +#define AVUTIL_ATOMIC_SUNCC_H + +#include +#include + +#include "atomic.h" + +#define avpriv_atomic_int_get atomic_int_get_suncc +static inline int atomic_int_get_suncc(volatile int *ptr) +{ + __machine_rw_barrier(); + return *ptr; +} + +#define avpriv_atomic_int_set atomic_int_set_suncc +static inline void atomic_int_set_suncc(volatile int *ptr, int val) +{ + *ptr = val; + __machine_rw_barrier(); +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_suncc +static inline int atomic_int_add_and_fetch_suncc(volatile int *ptr, int inc) +{ + return atomic_add_int_nv(ptr, inc); +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_suncc +static inline void *atomic_ptr_cas_suncc(void * volatile *ptr, + void *oldval, void *newval) +{ + return atomic_cas_ptr(ptr, oldval, newval); +} + +#endif /* AVUTIL_ATOMIC_SUNCC_H */ diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h new file mode 100644 index 0000000..20b99df --- /dev/null +++ b/libavutil/atomic_win32.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATOMIC_WIN32_H +#define AVUTIL_ATOMIC_WIN32_H + +#include + +#define avpriv_atomic_int_get atomic_int_get_win32 +static inline int atomic_int_get_win32(volatile int *ptr) +{ + MemoryBarrier(); + return *ptr; +} + +#define avpriv_atomic_int_set atomic_int_set_win32 +static inline void atomic_int_set_win32(volatile int *ptr, int val) +{ + *ptr = val; + MemoryBarrier(); +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32 +static inline int atomic_int_add_and_fetch_win32(volatile int *ptr, int inc) +{ + return inc + InterlockedExchangeAdd(ptr, inc); +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_win32 +static inline void *atomic_ptr_cas_win32(void * volatile *ptr, + void *oldval, void *newval) +{ + return InterlockedCompareExchangePointer(ptr, newval, oldval); +} + +#endif /* AVUTIL_ATOMIC_WIN32_H */ diff --git a/libavutil/attributes.h b/libavutil/attributes.h new file mode 100644 index 0000000..7d3f4a9 --- /dev/null +++ b/libavutil/attributes.h @@ -0,0 +1,160 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y) +#else +# define AV_GCC_VERSION_AT_LEAST(x,y) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline +#else +# define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) +#else +# define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_pure __attribute__((pure)) +#else +# define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,6) +# define av_const __attribute__((const)) +#else +# define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) +# define av_cold __attribute__((cold)) +#else +# define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) +# define av_flatten __attribute__((flatten)) +#else +# define av_flatten +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) +#else +# define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + + +#if defined(__GNUC__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_used __attribute__((used)) +#else +# define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,3) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) +# define av_uninit(x) x=x +#else +# define av_uninit(x) x +#endif + +#ifdef __GNUC__ +# define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) +#else +# define av_builtin_constant_p(x) 0 +# define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,5) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/libavutil/audio_fifo.h b/libavutil/audio_fifo.h new file mode 100644 index 0000000..d21e6a1 --- /dev/null +++ b/libavutil/audio_fifo.h @@ -0,0 +1,153 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/libavutil/audioconvert.h b/libavutil/audioconvert.h new file mode 100644 index 0000000..300a67c --- /dev/null +++ b/libavutil/audioconvert.h @@ -0,0 +1,6 @@ + +#include "version.h" + +#if FF_API_AUDIOCONVERT +#include "channel_layout.h" +#endif diff --git a/libavutil/avassert.h b/libavutil/avassert.h new file mode 100644 index 0000000..41f5e0e --- /dev/null +++ b/libavutil/avassert.h @@ -0,0 +1,66 @@ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speedloss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#else +#define av_assert2(cond) ((void)0) +#endif + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/libavutil/avconfig.h b/libavutil/avconfig.h new file mode 100644 index 0000000..123b3b2 --- /dev/null +++ b/libavutil/avconfig.h @@ -0,0 +1,7 @@ +/* Generated by ffconf */ +#ifndef AVUTIL_AVCONFIG_H +#define AVUTIL_AVCONFIG_H +#define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 0 +#define AV_HAVE_INCOMPATIBLE_LIBAV_ABI 0 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/libavutil/avstring.h b/libavutil/avstring.h new file mode 100644 index 0000000..ffb7aa6 --- /dev/null +++ b/libavutil/avstring.h @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to a av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +av_const int av_isdigit(int c); + +/** + * Locale-independent conversion of ASCII isgraph. + */ +av_const int av_isgraph(int c); + +/** + * Locale-independent conversion of ASCII isspace. + */ +av_const int av_isspace(int c); + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline av_const int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline av_const int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +av_const int av_isxdigit(int c); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE 0x01 + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT 0x02 + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * Check if a name is in a list. + * @returns 0 if not found, or the 1 based index where it has been found in the + * list. + */ +int av_match_list(const char *name, const char *list, char separator); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/libavutil/avutil.h b/libavutil/avutil.h new file mode 100644 index 0000000..e6ebb6c --- /dev/null +++ b/libavutil/avutil.h @@ -0,0 +1,344 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVUTIL_H +#define AVUTIL_AVUTIL_H + +/** + * @file + * external API header + */ + +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ + +/** + * @defgroup lavu Common utility functions + * + * @brief + * libavutil contains the code shared across all the other FFmpeg + * libraries + * + * @note In order to use the functions provided by avutil you must include + * the specific header. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Maths + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup lavu_internal Internal + * + * Not exported functions, for internal usage only + * + * @{ + * + * @} + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ + + +/** + * @addtogroup lavu_ver + * @{ + */ + +/** + * Return the LIBAVUTIL_VERSION_INT constant. + */ +unsigned avutil_version(void); + +/** + * Return the libavutil build-time configuration. + */ +const char *avutil_configuration(void); + +/** + * Return the libavutil license. + */ +const char *avutil_license(void); + +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + +enum AVMediaType { + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA + AVMEDIA_TYPE_VIDEO, + AVMEDIA_TYPE_AUDIO, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous + AVMEDIA_TYPE_SUBTITLE, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse + AVMEDIA_TYPE_NB +}; + +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1< + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/libavutil/blowfish.h b/libavutil/blowfish.h new file mode 100644 index 0000000..0b00453 --- /dev/null +++ b/libavutil/blowfish.h @@ -0,0 +1,77 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/libavutil/bprint.h b/libavutil/bprint.h new file mode 100644 index 0000000..d1682fc --- /dev/null +++ b/libavutil/bprint.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ +#define FF_PAD_STRUCTURE(size, ...) \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct { __VA_ARGS__ })]; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ +typedef struct AVBPrint { + FF_PAD_STRUCTURE(1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; + ) +} AVBPrint; + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(const AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ diff --git a/libavutil/bswap.h b/libavutil/bswap.h new file mode 100644 index 0000000..91cb795 --- /dev/null +++ b/libavutil/bswap.h @@ -0,0 +1,109 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/libavutil/buffer.c b/libavutil/buffer.c new file mode 100644 index 0000000..e9bf54b --- /dev/null +++ b/libavutil/buffer.c @@ -0,0 +1,358 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "atomic.h" +#include "buffer_internal.h" +#include "common.h" +#include "mem.h" + +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags) +{ + AVBufferRef *ref = NULL; + AVBuffer *buf = NULL; + + buf = av_mallocz(sizeof(*buf)); + if (!buf) + return NULL; + + buf->data = data; + buf->size = size; + buf->free = free ? free : av_buffer_default_free; + buf->opaque = opaque; + buf->refcount = 1; + + if (flags & AV_BUFFER_FLAG_READONLY) + buf->flags |= BUFFER_FLAG_READONLY; + + ref = av_mallocz(sizeof(*ref)); + if (!ref) { + av_freep(&buf); + return NULL; + } + + ref->buffer = buf; + ref->data = data; + ref->size = size; + + return ref; +} + +void av_buffer_default_free(void *opaque, uint8_t *data) +{ + av_free(data); +} + +AVBufferRef *av_buffer_alloc(int size) +{ + AVBufferRef *ret = NULL; + uint8_t *data = NULL; + + data = av_malloc(size); + if (!data) + return NULL; + + ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!ret) + av_freep(&data); + + return ret; +} + +AVBufferRef *av_buffer_allocz(int size) +{ + AVBufferRef *ret = av_buffer_alloc(size); + if (!ret) + return NULL; + + memset(ret->data, 0, size); + return ret; +} + +AVBufferRef *av_buffer_ref(AVBufferRef *buf) +{ + AVBufferRef *ret = av_mallocz(sizeof(*ret)); + + if (!ret) + return NULL; + + *ret = *buf; + + avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 1); + + return ret; +} + +void av_buffer_unref(AVBufferRef **buf) +{ + AVBuffer *b; + + if (!buf || !*buf) + return; + b = (*buf)->buffer; + av_freep(buf); + + if (!avpriv_atomic_int_add_and_fetch(&b->refcount, -1)) { + b->free(b->opaque, b->data); + av_freep(&b); + } +} + +int av_buffer_is_writable(const AVBufferRef *buf) +{ + if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY) + return 0; + + return avpriv_atomic_int_get(&buf->buffer->refcount) == 1; +} + +void *av_buffer_get_opaque(const AVBufferRef *buf) +{ + return buf->buffer->opaque; +} + +int av_buffer_get_ref_count(const AVBufferRef *buf) +{ + return buf->buffer->refcount; +} + +int av_buffer_make_writable(AVBufferRef **pbuf) +{ + AVBufferRef *newbuf, *buf = *pbuf; + + if (av_buffer_is_writable(buf)) + return 0; + + newbuf = av_buffer_alloc(buf->size); + if (!newbuf) + return AVERROR(ENOMEM); + + memcpy(newbuf->data, buf->data, buf->size); + av_buffer_unref(pbuf); + *pbuf = newbuf; + + return 0; +} + +int av_buffer_realloc(AVBufferRef **pbuf, int size) +{ + AVBufferRef *buf = *pbuf; + uint8_t *tmp; + + if (!buf) { + /* allocate a new buffer with av_realloc(), so it will be reallocatable + * later */ + uint8_t *data = av_realloc(NULL, size); + if (!data) + return AVERROR(ENOMEM); + + buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!buf) { + av_freep(&data); + return AVERROR(ENOMEM); + } + + buf->buffer->flags |= BUFFER_FLAG_REALLOCATABLE; + *pbuf = buf; + + return 0; + } else if (buf->size == size) + return 0; + + if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) || + !av_buffer_is_writable(buf)) { + /* cannot realloc, allocate a new reallocable buffer and copy data */ + AVBufferRef *new = NULL; + + av_buffer_realloc(&new, size); + if (!new) + return AVERROR(ENOMEM); + + memcpy(new->data, buf->data, FFMIN(size, buf->size)); + + av_buffer_unref(pbuf); + *pbuf = new; + return 0; + } + + tmp = av_realloc(buf->buffer->data, size); + if (!tmp) + return AVERROR(ENOMEM); + + buf->buffer->data = buf->data = tmp; + buf->buffer->size = buf->size = size; + return 0; +} + +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)) +{ + AVBufferPool *pool = av_mallocz(sizeof(*pool)); + if (!pool) + return NULL; + + pool->size = size; + pool->alloc = alloc ? alloc : av_buffer_alloc; + + avpriv_atomic_int_set(&pool->refcount, 1); + + return pool; +} + +/* + * This function gets called when the pool has been uninited and + * all the buffers returned to it. + */ +static void buffer_pool_free(AVBufferPool *pool) +{ + while (pool->pool) { + BufferPoolEntry *buf = pool->pool; + pool->pool = buf->next; + + buf->free(buf->opaque, buf->data); + av_freep(&buf); + } + av_freep(&pool); +} + +void av_buffer_pool_uninit(AVBufferPool **ppool) +{ + AVBufferPool *pool; + + if (!ppool || !*ppool) + return; + pool = *ppool; + *ppool = NULL; + + if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1)) + buffer_pool_free(pool); +} + +/* remove the whole buffer list from the pool and return it */ +static BufferPoolEntry *get_pool(AVBufferPool *pool) +{ + BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL; + + while (cur != last) { + last = cur; + cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL); + if (!cur) + return NULL; + } + + return cur; +} + +static void add_to_pool(BufferPoolEntry *buf) +{ + AVBufferPool *pool; + BufferPoolEntry *cur, *end = buf; + + if (!buf) + return; + pool = buf->pool; + + while (end->next) + end = end->next; + + while (avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf)) { + /* pool is not empty, retrieve it and append it to our list */ + cur = get_pool(pool); + end->next = cur; + while (end->next) + end = end->next; + } +} + +static void pool_release_buffer(void *opaque, uint8_t *data) +{ + BufferPoolEntry *buf = opaque; + AVBufferPool *pool = buf->pool; + + if(CONFIG_MEMORY_POISONING) + memset(buf->data, FF_MEMORY_POISON, pool->size); + + add_to_pool(buf); + if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1)) + buffer_pool_free(pool); +} + +/* allocate a new buffer and override its free() callback so that + * it is returned to the pool on free */ +static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) +{ + BufferPoolEntry *buf; + AVBufferRef *ret; + + ret = pool->alloc(pool->size); + if (!ret) + return NULL; + + buf = av_mallocz(sizeof(*buf)); + if (!buf) { + av_buffer_unref(&ret); + return NULL; + } + + buf->data = ret->buffer->data; + buf->opaque = ret->buffer->opaque; + buf->free = ret->buffer->free; + buf->pool = pool; + + ret->buffer->opaque = buf; + ret->buffer->free = pool_release_buffer; + + avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); + avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1); + + return ret; +} + +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) +{ + AVBufferRef *ret; + BufferPoolEntry *buf; + + /* check whether the pool is empty */ + buf = get_pool(pool); + if (!buf && pool->refcount <= pool->nb_allocated) { + av_log(NULL, AV_LOG_DEBUG, "Pool race dectected, spining to avoid overallocation and eventual OOM\n"); + while (!buf && avpriv_atomic_int_get(&pool->refcount) <= avpriv_atomic_int_get(&pool->nb_allocated)) + buf = get_pool(pool); + } + + if (!buf) + return pool_alloc_buffer(pool); + + /* keep the first entry, return the rest of the list to the pool */ + add_to_pool(buf->next); + buf->next = NULL; + + ret = av_buffer_create(buf->data, pool->size, pool_release_buffer, + buf, 0); + if (!ret) { + add_to_pool(buf); + return NULL; + } + avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); + + return ret; +} diff --git a/libavutil/buffer.h b/libavutil/buffer.h new file mode 100644 index 0000000..b4399fd --- /dev/null +++ b/libavutil/buffer.h @@ -0,0 +1,274 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + * @see av_buffer_pool_can_uninit() + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h new file mode 100644 index 0000000..c291908 --- /dev/null +++ b/libavutil/buffer_internal.h @@ -0,0 +1,94 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BUFFER_INTERNAL_H +#define AVUTIL_BUFFER_INTERNAL_H + +#include + +#include "buffer.h" + +/** + * The buffer is always treated as read-only. + */ +#define BUFFER_FLAG_READONLY (1 << 0) +/** + * The buffer was av_realloc()ed, so it is reallocatable. + */ +#define BUFFER_FLAG_REALLOCATABLE (1 << 1) + +struct AVBuffer { + uint8_t *data; /**< data described by this buffer */ + int size; /**< size of data in bytes */ + + /** + * number of existing AVBufferRef instances referring to this buffer + */ + volatile int refcount; + + /** + * a callback for freeing the data + */ + void (*free)(void *opaque, uint8_t *data); + + /** + * an opaque pointer, to be used by the freeing callback + */ + void *opaque; + + /** + * A combination of BUFFER_FLAG_* + */ + int flags; +}; + +typedef struct BufferPoolEntry { + uint8_t *data; + + /* + * Backups of the original opaque/free of the AVBuffer corresponding to + * data. They will be used to free the buffer when the pool is freed. + */ + void *opaque; + void (*free)(void *opaque, uint8_t *data); + + AVBufferPool *pool; + struct BufferPoolEntry * volatile next; +} BufferPoolEntry; + +struct AVBufferPool { + BufferPoolEntry * volatile pool; + + /* + * This is used to track when the pool is to be freed. + * The pointer to the pool itself held by the caller is considered to + * be one reference. Each buffer requested by the caller increases refcount + * by one, returning the buffer to the pool decreases it by one. + * refcount reaches zero when the buffer has been uninited AND all the + * buffers have been released, then it's safe to free the pool and all + * the buffers in it. + */ + volatile int refcount; + + volatile int nb_allocated; + + int size; + AVBufferRef* (*alloc)(int size); +}; + +#endif /* AVUTIL_BUFFER_INTERNAL_H */ diff --git a/libavutil/cast5.h b/libavutil/cast5.h new file mode 100644 index 0000000..a4df6d8 --- /dev/null +++ b/libavutil/cast5.h @@ -0,0 +1,67 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAST5_H +#define AVUTIL_CAST5_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAST5 algorithm + * @defgroup lavu_cast5 CAST5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_cast5_size; + +struct AVCAST5; + +/** + * Allocate an AVCAST5 context + * To free the struct: av_free(ptr) + */ +struct AVCAST5 *av_cast5_alloc(void); +/** + * Initialize an AVCAST5 context. + * + * @param ctx an AVCAST5 context + * @param key a key of 5,6,...16 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 40,48,...,128 + */ +int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count,int decrypt); +/** + * @} + */ +#endif /* AVUTIL_CAST5_H */ diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h new file mode 100644 index 0000000..dea4d60 --- /dev/null +++ b/libavutil/channel_layout.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, optionally followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * @warning Starting from the next major bump the trailing character + * 'c' to specify a number of channels will be required, while a + * channel layout mask could also be specified as a decimal number + * (if and only if not followed by "c"). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/libavutil/colorspace.h b/libavutil/colorspace.h new file mode 100644 index 0000000..f438159 --- /dev/null +++ b/libavutil/colorspace.h @@ -0,0 +1,111 @@ +/* + * Colorspace conversion defines + * Copyright (c) 2001, 2002, 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Various defines for YUV<->RGB conversion + */ + +#ifndef AVUTIL_COLORSPACE_H +#define AVUTIL_COLORSPACE_H + +#define SCALEBITS 10 +#define ONE_HALF (1 << (SCALEBITS - 1)) +#define FIX(x) ((int) ((x) * (1<> SCALEBITS];\ + g = cm[(y + g_add) >> SCALEBITS];\ + b = cm[(y + b_add) >> SCALEBITS];\ +} + +#define YUV_TO_RGB1(cb1, cr1)\ +{\ + cb = (cb1) - 128;\ + cr = (cr1) - 128;\ + r_add = FIX(1.40200) * cr + ONE_HALF;\ + g_add = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;\ + b_add = FIX(1.77200) * cb + ONE_HALF;\ +} + +#define YUV_TO_RGB2(r, g, b, y1)\ +{\ + y = (y1) << SCALEBITS;\ + r = cm[(y + r_add) >> SCALEBITS];\ + g = cm[(y + g_add) >> SCALEBITS];\ + b = cm[(y + b_add) >> SCALEBITS];\ +} + +#define Y_CCIR_TO_JPEG(y)\ + cm[((y) * FIX(255.0/219.0) + (ONE_HALF - 16 * FIX(255.0/219.0))) >> SCALEBITS] + +#define Y_JPEG_TO_CCIR(y)\ + (((y) * FIX(219.0/255.0) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define C_CCIR_TO_JPEG(y)\ + cm[(((y) - 128) * FIX(127.0/112.0) + (ONE_HALF + (128 << SCALEBITS))) >> SCALEBITS] + +/* NOTE: the clamp is really necessary! */ +static inline int C_JPEG_TO_CCIR(int y) { + y = (((y - 128) * FIX(112.0/127.0) + (ONE_HALF + (128 << SCALEBITS))) >> SCALEBITS); + if (y < 16) + y = 16; + return y; +} + + +#define RGB_TO_Y(r, g, b) \ +((FIX(0.29900) * (r) + FIX(0.58700) * (g) + \ + FIX(0.11400) * (b) + ONE_HALF) >> SCALEBITS) + +#define RGB_TO_U(r1, g1, b1, shift)\ +(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + \ + FIX(0.50000) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_V(r1, g1, b1, shift)\ +(((FIX(0.50000) * r1 - FIX(0.41869) * g1 - \ + FIX(0.08131) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_Y_CCIR(r, g, b) \ +((FIX(0.29900*219.0/255.0) * (r) + FIX(0.58700*219.0/255.0) * (g) + \ + FIX(0.11400*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define RGB_TO_U_CCIR(r1, g1, b1, shift)\ +(((- FIX(0.16874*224.0/255.0) * r1 - FIX(0.33126*224.0/255.0) * g1 + \ + FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_V_CCIR(r1, g1, b1, shift)\ +(((FIX(0.50000*224.0/255.0) * r1 - FIX(0.41869*224.0/255.0) * g1 - \ + FIX(0.08131*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#endif /* AVUTIL_COLORSPACE_H */ diff --git a/libavutil/common.h b/libavutil/common.h new file mode 100644 index 0000000..c82a3a6 --- /dev/null +++ b/libavutil/common.h @@ -0,0 +1,469 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal and external API header + */ + +#ifndef AVUTIL_COMMON_H +#define AVUTIL_COMMON_H + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "version.h" +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* assume a>0 and b>0 */ +#define FF_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +/* misc math functions */ + +/** + * Reverse the order of the bits of an 8-bits unsigned integer. + */ +#if FF_API_AV_REVERSE +extern attribute_deprecated const uint8_t av_reverse[256]; +#endif + +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +# include "intmath.h" +#endif + +/* Pull in unguarded fallback defines at the end of this file. */ +#include "common.h" + +#ifndef av_log2 +av_const int av_log2(unsigned v); +#endif + +#ifndef av_log2_16bit +av_const int av_log2_16bit(unsigned v); +#endif + +/** + * Clip a signed integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed 64bit integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed integer value into the 0-255 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1<> 31 & ((1<= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a double value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** Compute ceil(log2(x)). + * @param x value used to compute ceil(log2(x)) + * @return computed ceiling of log2(x) + */ +static av_always_inline av_const int av_ceil_log2_c(int x) +{ + return av_log2((x - 1) << 1); +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= GET_BYTE;\ + {\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ + ERROR\ + while (val & top) {\ + int tmp= GET_BYTE - 128;\ + if(tmp>>6)\ + ERROR\ + val= (val<<6) + tmp;\ + top <<= 5;\ + }\ + val &= (top << 1) - 1;\ + } + +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + */ +#define GET_UTF16(val, GET_16BIT, ERROR)\ + val = GET_16BIT;\ + {\ + unsigned int hi = val - 0xD800;\ + if (hi < 0x800) {\ + val = GET_16BIT - 0xDC00;\ + if (val > 0x3FFU || hi > 0x3FFU)\ + ERROR\ + val += (hi<<10) + 0x10000;\ + }\ + }\ + +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_BYTE. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid UTF-8 range and up to + * 7 times in the general case, depending on the length of the converted + * Unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint16_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_16BIT. + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination + * in desired endianness. It could be a function or a statement, and uses tmp + * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" + * PUT_BYTE will be executed 1 or 2 times depending on input character. + */ +#define PUT_UTF16(val, tmp, PUT_16BIT)\ + {\ + uint32_t in = val;\ + if (in < 0x10000) {\ + tmp = in;\ + PUT_16BIT\ + } else {\ + tmp = 0xD800 | ((in - 0x10000) >> 10);\ + PUT_16BIT\ + tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ + PUT_16BIT\ + }\ + }\ + + + +#include "mem.h" + +#ifdef HAVE_AV_CONFIG_H +# include "internal.h" +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* AVUTIL_COMMON_H */ + +/* + * The following definitions are outside the multiple inclusion guard + * to ensure they are immediately available in intmath.h. + */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif diff --git a/libavutil/cpu.h b/libavutil/cpu.h new file mode 100644 index 0000000..277e489 --- /dev/null +++ b/libavutil/cpu.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +// #if LIBAVUTIL_VERSION_MAJOR <52 +#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction +// #else +// #define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +// #endif +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in a application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + * + * @warning this function is not thread safe. + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/libavutil/cpu_internal.h b/libavutil/cpu_internal.h new file mode 100644 index 0000000..3c6ce6d --- /dev/null +++ b/libavutil/cpu_internal.h @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_INTERNAL_H +#define AVUTIL_CPU_INTERNAL_H + +#include "cpu.h" + +#define CPUEXT_SUFFIX(flags, suffix, cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext)) + +#define CPUEXT(flags, cpuext) CPUEXT_SUFFIX(flags, , cpuext) + +int ff_get_cpu_flags_aarch64(void); +int ff_get_cpu_flags_arm(void); +int ff_get_cpu_flags_ppc(void); +int ff_get_cpu_flags_x86(void); + +#endif /* AVUTIL_CPU_INTERNAL_H */ diff --git a/libavutil/crc.h b/libavutil/crc.h new file mode 100644 index 0000000..e86bf1d --- /dev/null +++ b/libavutil/crc.h @@ -0,0 +1,86 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" + +/** + * @defgroup lavu_crc32 CRC32 + * @ingroup lavu_crypto + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ + AV_CRC_24_IEEE = 12, + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/libavutil/des.h b/libavutil/des.h new file mode 100644 index 0000000..2feb046 --- /dev/null +++ b/libavutil/des.h @@ -0,0 +1,61 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DES_H +#define AVUTIL_DES_H + +#include + +struct AVDES { + uint64_t round_keys[3][16]; + int triple_des; +}; + +/** + * @brief Initializes an AVDES context. + * + * @param key_bits must be 64 or 192 + * @param decrypt 0 for encryption/CBC-MAC, 1 for decryption + */ +int av_des_init(struct AVDES *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param iv initialization vector for CBC mode, if NULL then ECB will be used, + * must be 8-byte aligned + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_des_crypt(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @brief Calculates CBC-MAC using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + */ +void av_des_mac(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count); + +#endif /* AVUTIL_DES_H */ diff --git a/libavutil/dict.h b/libavutil/dict.h new file mode 100644 index 0000000..9b3381b --- /dev/null +++ b/libavutil/dict.h @@ -0,0 +1,178 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + * + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(FF_CONST_AVUTIL53 AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will be av_strduped depending on flags) + * @param value entry value to add to *pm (will be av_strduped depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + */ +void av_dict_copy(AVDictionary **dst, FF_CONST_AVUTIL53 AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/libavutil/display.h b/libavutil/display.h new file mode 100644 index 0000000..2cb930d --- /dev/null +++ b/libavutil/display.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include + +/** + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * + * The transformation can also be more explicitly written in components as + * follows: + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame. + * The angle will be in range [-180.0, 180.0], or NaN if the matrix is + * singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure rotation by the + * specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/libavutil/downmix_info.h b/libavutil/downmix_info.h new file mode 100644 index 0000000..221cf5b --- /dev/null +++ b/libavutil/downmix_info.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/libavutil/dynarray.h b/libavutil/dynarray.h new file mode 100644 index 0000000..4947d93 --- /dev/null +++ b/libavutil/dynarray.h @@ -0,0 +1,70 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DYNARRAY_H +#define AVUTIL_DYNARRAY_H + +#include "log.h" +#include "mem.h" + +/** + * Add an element of to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the size is incremented. + * + * @param av_size_max maximum size of the array, usually the MAX macro of + * the type of the size + * @param av_elt_size size of the elements in the array, in bytes + * @param av_array pointer to the array, must be a lvalue + * @param av_size size of the array, must be an integer lvalue + * @param av_success statement to execute on success; at this point, the + * size variable is not yet incremented + * @param av_failure statement to execute on failure; if this happens, the + * array and size are not changed; the statement can end + * with a return or a goto + */ +#define AV_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, \ + av_success, av_failure) \ + do { \ + size_t av_size_new = (av_size); \ + if (!((av_size) & ((av_size) - 1))) { \ + av_size_new = (av_size) ? (av_size) << 1 : 1; \ + if (av_size_new > (av_size_max) / (av_elt_size)) { \ + av_size_new = 0; \ + } else { \ + void *av_array_new = \ + av_realloc((av_array), av_size_new * (av_elt_size)); \ + if (!av_array_new) \ + av_size_new = 0; \ + else \ + (av_array) = av_array_new; \ + } \ + } \ + if (av_size_new) { \ + { av_success } \ + (av_size)++; \ + } else { \ + av_failure \ + } \ + } while (0) + +#endif /* AVUTIL_DYNARRAY_H */ diff --git a/libavutil/error.h b/libavutil/error.h new file mode 100644 index 0000000..71df4da --- /dev/null +++ b/libavutil/error.h @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * error code definitions + */ + +#ifndef AVUTIL_ERROR_H +#define AVUTIL_ERROR_H + +#include +#include + +/** + * @addtogroup lavu_error + * + * @{ + */ + + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found + +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) +/* HTTP & RTSP errors */ +#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') +#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') +#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') +#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') +#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') + +#define AV_ERROR_MAX_STRING_SIZE 64 + +/** + * Put a description of the AVERROR code errnum in errbuf. + * In case of failure the global variable errno is set to indicate the + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. + * + * @param errnum error code to describe + * @param errbuf buffer to which description is written + * @param errbuf_size the size in bytes of errbuf + * @return 0 on success, a negative value if a description for errnum + * cannot be found + */ +int av_strerror(int errnum, char *errbuf, size_t errbuf_size); + +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + +#endif /* AVUTIL_ERROR_H */ diff --git a/libavutil/eval.h b/libavutil/eval.h new file mode 100644 index 0000000..6159b0f --- /dev/null +++ b/libavutil/eval.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value for + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/libavutil/ffversion.h b/libavutil/ffversion.h new file mode 100644 index 0000000..0ad698e --- /dev/null +++ b/libavutil/ffversion.h @@ -0,0 +1,4 @@ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "N-67732-g530eb6a" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/libavutil/fifo.h b/libavutil/fifo.h new file mode 100644 index 0000000..dda7dd2 --- /dev/null +++ b/libavutil/fifo.h @@ -0,0 +1,158 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ diff --git a/libavutil/file.h b/libavutil/file.h new file mode 100644 index 0000000..a7364fe --- /dev/null +++ b/libavutil/file.h @@ -0,0 +1,66 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or -1 on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ diff --git a/libavutil/fixed_dsp.h b/libavutil/fixed_dsp.h new file mode 100644 index 0000000..ff6f365 --- /dev/null +++ b/libavutil/fixed_dsp.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Nedeljko Babic (nbabic@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FIXED_DSP_H +#define AVUTIL_FIXED_DSP_H + +#include +#include "attributes.h" +#include "common.h" +#include "libavcodec/mathops.h" + +typedef struct AVFixedDSPContext { + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + * @param bits scaling parameter + * + */ + void (*vector_fmul_window_scaled)(int16_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len, uint8_t bits); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(int32_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len); + +} AVFixedDSPContext; + +/** + * Allocate and initialize a fixed DSP context. + * note: should be freed with a av_free call when no longer needed. + * + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +AVFixedDSPContext * avpriv_alloc_fixed_dsp(int strict); + +/** + * Calculate the square root + * + * @param x input fixed point number + * + * @param bits format of fixed point number (32 - bits).bits + * + * note: input is normalized to (0, 1) fixed point value + */ + +static av_always_inline int fixed_sqrt(int x, int bits) +{ + int retval, bit_mask, guess, square, i; + int64_t accu; + int shift1 = 30 - bits; + int shift2 = bits - 15; + + if (shift1 > 0) retval = ff_sqrt(x << shift1); + else retval = ff_sqrt(x >> -shift1); + + if (shift2 > 0) { + retval = retval << shift2; + bit_mask = (1 << (shift2 - 1)); + + for (i=0; i> bits); + if (x >= square) + retval += bit_mask; + bit_mask >>= 1; + } + + } + else retval >>= (-shift2); + + return retval; +} + +#endif /* AVUTIL_FIXED_DSP_H */ diff --git a/libavutil/float_dsp.h b/libavutil/float_dsp.h new file mode 100644 index 0000000..7fc851b --- /dev/null +++ b/libavutil/float_dsp.h @@ -0,0 +1,188 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FLOAT_DSP_H +#define AVUTIL_FLOAT_DSP_H + +#include "config.h" + +typedef struct AVFloatDSPContext { + /** + * Calculate the product of two vectors of floats and store the result in + * a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul)(float *dst, const float *src0, const float *src1, + int len); + + /** + * Multiply a vector of floats by a scalar float and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_fmac_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of floats by a scalar float. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src input vector + * constraints: 16-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of double by a scalar double. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 8 + */ + void (*vector_dmul_scalar)(double *dst, const double *src, double mul, + int len); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(float *dst, const float *src0, + const float *src1, const float *win, int len); + + /** + * Calculate the product of two vectors of floats, add a third vector of + * floats and store the result in a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param src2 third input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_add)(float *dst, const float *src0, const float *src1, + const float *src2, int len); + + /** + * Calculate the product of two vectors of floats, and store the result + * in a vector of floats. The second vector of floats is iterated over + * in reverse order. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_reverse)(float *dst, const float *src0, + const float *src1, int len); + + /** + * Calculate the sum and difference of two vectors of floats. + * + * @param v1 first input vector, sum output, 16-byte aligned + * @param v2 second input vector, difference output, 16-byte aligned + * @param len length of vectors, multiple of 4 + */ + void (*butterflies_float)(float *av_restrict v1, float *av_restrict v2, int len); + + /** + * Calculate the scalar product of two vectors of floats. + * + * @param v1 first vector, 16-byte aligned + * @param v2 second vector, 16-byte aligned + * @param len length of vectors, multiple of 4 + * + * @return sum of elementwise products + */ + float (*scalarproduct_float)(const float *v1, const float *v2, int len); +} AVFloatDSPContext; + +/** + * Return the scalar product of two vectors. + * + * @param v1 first input vector + * @param v2 first input vector + * @param len number of elements + * + * @return sum of elementwise products + */ +float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len); + +/** + * Initialize a float DSP context. + * + * @param fdsp float DSP context + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int strict); + + +void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict); +void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp); + +#endif /* AVUTIL_FLOAT_DSP_H */ diff --git a/libavutil/frame.c b/libavutil/frame.c new file mode 100644 index 0000000..df8bac2 --- /dev/null +++ b/libavutil/frame.c @@ -0,0 +1,661 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "channel_layout.h" +#include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "dict.h" +#include "frame.h" +#include "imgutils.h" +#include "mem.h" +#include "samplefmt.h" + +MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_duration) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_pos) +MAKE_ACCESSORS(AVFrame, frame, int64_t, channel_layout) +MAKE_ACCESSORS(AVFrame, frame, int, channels) +MAKE_ACCESSORS(AVFrame, frame, int, sample_rate) +MAKE_ACCESSORS(AVFrame, frame, int, decode_error_flags) +MAKE_ACCESSORS(AVFrame, frame, int, pkt_size) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorSpace, colorspace) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorRange, color_range) + +#define CHECK_CHANNELS_CONSISTENCY(frame) \ + av_assert2(!(frame)->channel_layout || \ + (frame)->channels == \ + av_get_channel_layout_nb_channels((frame)->channel_layout)) + +static void get_frame_defaults(AVFrame *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->pts = + frame->pkt_dts = + frame->pkt_pts = AV_NOPTS_VALUE; + av_frame_set_best_effort_timestamp(frame, AV_NOPTS_VALUE); + av_frame_set_pkt_duration (frame, 0); + av_frame_set_pkt_pos (frame, -1); + av_frame_set_pkt_size (frame, -1); + frame->key_frame = 1; + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + frame->format = -1; /* unknown */ + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; +} + +static void free_side_data(AVFrameSideData **ptr_sd) +{ + AVFrameSideData *sd = *ptr_sd; + + av_freep(&sd->data); + av_freep(ptr_sd); +} + +AVFrame *av_frame_alloc(void) +{ + AVFrame *frame = av_mallocz(sizeof(*frame)); + + if (!frame) + return NULL; + + get_frame_defaults(frame); + + return frame; +} + +void av_frame_free(AVFrame **frame) +{ + if (!frame || !*frame) + return; + + av_frame_unref(*frame); + av_freep(frame); +} + +void av_frame_unref(AVFrame *frame) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + av_buffer_unref(&frame->buf[i]); + + get_frame_defaults(frame); +} + +void av_frame_move_ref(AVFrame *dst, AVFrame *src) +{ + *dst = *src; + memset(src, 0, sizeof(*src)); + get_frame_defaults(src); +} + +int av_frame_ref(AVFrame *dst, const AVFrame *src) +{ + int i, ret = 0; + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->channels = src->channels; + dst->channel_layout = src->channel_layout; + dst->nb_samples = src->nb_samples; + + /* duplicate the frame data if it's not refcounted */ + if (!src->buf[0]) { + abort(); +#if 0 + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(dst, src); + if (ret < 0) + av_frame_unref(dst); + + return ret; +#endif + } + + /* ref the buffers */ + for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +#if 0 +static int get_video_buffer(AVFrame *frame, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int ret, i; + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) + return ret; + + if (!frame->linesize[0]) { + for(i=1; i<=align; i+=i) { + ret = av_image_fill_linesizes(frame->linesize, frame->format, + FFALIGN(frame->width, i)); + if (ret < 0) + return ret; + if (!(frame->linesize[0] & (align-1))) + break; + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) + frame->linesize[i] = FFALIGN(frame->linesize[i], align); + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) { + int h = FFALIGN(frame->height, 32); + if (i == 1 || i == 2) + h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h); + + frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h + 16 + 16/*STRIDE_ALIGN*/ - 1); + if (!frame->buf[i]) + goto fail; + + frame->data[i] = frame->buf[i]->data; + } + if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + av_buffer_unref(&frame->buf[1]); + frame->buf[1] = av_buffer_alloc(1024); + if (!frame->buf[1]) + goto fail; + frame->data[1] = frame->buf[1]->data; + } + + frame->extended_data = frame->data; + + return 0; +fail: + av_frame_unref(frame); + return AVERROR(ENOMEM); +} + +static int get_audio_buffer(AVFrame *frame, int align) +{ + int channels; + int planar = av_sample_fmt_is_planar(frame->format); + int planes; + int ret, i; + + if (!frame->channels) + frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout); + + channels = frame->channels; + planes = planar ? channels : 1; + + CHECK_CHANNELS_CONSISTENCY(frame); + if (!frame->linesize[0]) { + ret = av_samples_get_buffer_size(&frame->linesize[0], channels, + frame->nb_samples, frame->format, + align); + if (ret < 0) + return ret; + } + + if (planes > AV_NUM_DATA_POINTERS) { + frame->extended_data = av_mallocz_array(planes, + sizeof(*frame->extended_data)); + frame->extended_buf = av_mallocz_array((planes - AV_NUM_DATA_POINTERS), + sizeof(*frame->extended_buf)); + if (!frame->extended_data || !frame->extended_buf) { + av_freep(&frame->extended_data); + av_freep(&frame->extended_buf); + return AVERROR(ENOMEM); + } + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; + } else + frame->extended_data = frame->data; + + for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { + frame->buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; + } + for (i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { + frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->extended_buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data; + } + return 0; + +} + +int av_frame_get_buffer(AVFrame *frame, int align) +{ + if (frame->format < 0) + return AVERROR(EINVAL); + + if (frame->width > 0 && frame->height > 0) + return get_video_buffer(frame, align); + else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0)) + return get_audio_buffer(frame, align); + + return AVERROR(EINVAL); +} + + +int av_frame_ref(AVFrame *dst, const AVFrame *src) +{ + int i, ret = 0; + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->channels = src->channels; + dst->channel_layout = src->channel_layout; + dst->nb_samples = src->nb_samples; + + ret = av_frame_copy_props(dst, src); + if (ret < 0) + return ret; + + /* duplicate the frame data if it's not refcounted */ + if (!src->buf[0]) { + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(dst, src); + if (ret < 0) + av_frame_unref(dst); + + return ret; + } + + /* ref the buffers */ + for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if (src->extended_buf) { + dst->extended_buf = av_mallocz_array(sizeof(*dst->extended_buf), + src->nb_extended_buf); + if (!dst->extended_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->nb_extended_buf = src->nb_extended_buf; + + for (i = 0; i < src->nb_extended_buf; i++) { + dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]); + if (!dst->extended_buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + + /* duplicate extended data */ + if (src->extended_data != src->data) { + int ch = src->channels; + + if (!ch) { + ret = AVERROR(EINVAL); + goto fail; + } + CHECK_CHANNELS_CONSISTENCY(src); + + dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch); + if (!dst->extended_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + memcpy(dst->extended_data, src->extended_data, sizeof(*src->extended_data) * ch); + } else + dst->extended_data = dst->data; + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +AVFrame *av_frame_clone(const AVFrame *src) +{ + AVFrame *ret = av_frame_alloc(); + + if (!ret) + return NULL; + + if (av_frame_ref(ret, src) < 0) + av_frame_free(&ret); + + return ret; +} + +int av_frame_is_writable(AVFrame *frame) +{ + int i, ret = 1; + + /* assume non-refcounted frames are not writable */ + if (!frame->buf[0]) + return 0; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + if (frame->buf[i]) + ret &= !!av_buffer_is_writable(frame->buf[i]); + for (i = 0; i < frame->nb_extended_buf; i++) + ret &= !!av_buffer_is_writable(frame->extended_buf[i]); + + return ret; +} + +int av_frame_make_writable(AVFrame *frame) +{ + AVFrame tmp; + int ret; + + if (!frame->buf[0]) + return AVERROR(EINVAL); + + if (av_frame_is_writable(frame)) + return 0; + + memset(&tmp, 0, sizeof(tmp)); + tmp.format = frame->format; + tmp.width = frame->width; + tmp.height = frame->height; + tmp.channels = frame->channels; + tmp.channel_layout = frame->channel_layout; + tmp.nb_samples = frame->nb_samples; + ret = av_frame_get_buffer(&tmp, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + ret = av_frame_copy_props(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + av_frame_unref(frame); + + *frame = tmp; + if (tmp.data == tmp.extended_data) + frame->extended_data = frame->data; + + return 0; +} + +int av_frame_copy_props(AVFrame *dst, const AVFrame *src) +{ + int i; + + dst->key_frame = src->key_frame; + dst->pict_type = src->pict_type; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->pts = src->pts; + dst->repeat_pict = src->repeat_pict; + dst->interlaced_frame = src->interlaced_frame; + dst->top_field_first = src->top_field_first; + dst->palette_has_changed = src->palette_has_changed; + dst->sample_rate = src->sample_rate; + dst->opaque = src->opaque; + dst->pkt_pts = src->pkt_pts; + dst->pkt_dts = src->pkt_dts; + dst->pkt_pos = src->pkt_pos; + dst->pkt_size = src->pkt_size; + dst->pkt_duration = src->pkt_duration; + dst->reordered_opaque = src->reordered_opaque; + dst->quality = src->quality; + dst->best_effort_timestamp = src->best_effort_timestamp; + dst->coded_picture_number = src->coded_picture_number; + dst->display_picture_number = src->display_picture_number; + dst->flags = src->flags; + dst->decode_error_flags = src->decode_error_flags; + dst->color_primaries = src->color_primaries; + dst->color_trc = src->color_trc; + dst->colorspace = src->colorspace; + dst->color_range = src->color_range; + dst->chroma_location = src->chroma_location; + + memcpy(dst->error, src->error, sizeof(dst->error)); + + for (i = 0; i < src->nb_side_data; i++) { + const AVFrameSideData *sd_src = src->side_data[i]; + AVFrameSideData *sd_dst; + if ( sd_src->type == AV_FRAME_DATA_PANSCAN + && (src->width != dst->width || src->height != dst->height)) + continue; + sd_dst = av_frame_new_side_data(dst, sd_src->type, + sd_src->size); + if (!sd_dst) { + for (i = 0; i < dst->nb_side_data; i++) { + free_side_data(&dst->side_data[i]); + } + av_freep(&dst->side_data); + return AVERROR(ENOMEM); + } + memcpy(sd_dst->data, sd_src->data, sd_src->size); + } + + return 0; +} + +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane) +{ + uint8_t *data; + int planes, i; + + if (frame->nb_samples) { + int channels = frame->channels; + if (!channels) + return NULL; + CHECK_CHANNELS_CONSISTENCY(frame); + planes = av_sample_fmt_is_planar(frame->format) ? channels : 1; + } else + planes = 4; + + if (plane < 0 || plane >= planes || !frame->extended_data[plane]) + return NULL; + data = frame->extended_data[plane]; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) { + AVBufferRef *buf = frame->buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + for (i = 0; i < frame->nb_extended_buf; i++) { + AVBufferRef *buf = frame->extended_buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + return NULL; +} + +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size) +{ + AVFrameSideData *ret, **tmp; + + if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) + return NULL; + + tmp = av_realloc(frame->side_data, + (frame->nb_side_data + 1) * sizeof(*frame->side_data)); + if (!tmp) + return NULL; + frame->side_data = tmp; + + ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + ret->data = av_malloc(size); + if (!ret->data) { + av_freep(&ret); + return NULL; + } + + ret->size = size; + ret->type = type; + + frame->side_data[frame->nb_side_data++] = ret; + + return ret; +} + +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type == type) + return frame->side_data[i]; + } + return NULL; +} + +static int frame_copy_video(AVFrame *dst, const AVFrame *src) +{ + const uint8_t *src_data[4]; + int i, planes; + + if (dst->width < src->width || + dst->height < src->height) + return AVERROR(EINVAL); + + planes = av_pix_fmt_count_planes(dst->format); + for (i = 0; i < planes; i++) + if (!dst->data[i] || !src->data[i]) + return AVERROR(EINVAL); + + memcpy(src_data, src->data, sizeof(src_data)); + av_image_copy(dst->data, dst->linesize, + src_data, src->linesize, + dst->format, src->width, src->height); + + return 0; +} + +static int frame_copy_audio(AVFrame *dst, const AVFrame *src) +{ + int planar = av_sample_fmt_is_planar(dst->format); + int channels = dst->channels; + int planes = planar ? channels : 1; + int i; + + if (dst->nb_samples != src->nb_samples || + dst->channels != src->channels || + dst->channel_layout != src->channel_layout) + return AVERROR(EINVAL); + + CHECK_CHANNELS_CONSISTENCY(src); + + for (i = 0; i < planes; i++) + if (!dst->extended_data[i] || !src->extended_data[i]) + return AVERROR(EINVAL); + + av_samples_copy(dst->extended_data, src->extended_data, 0, 0, + dst->nb_samples, channels, dst->format); + + return 0; +} + +int av_frame_copy(AVFrame *dst, const AVFrame *src) +{ + if (dst->format != src->format || dst->format < 0) + return AVERROR(EINVAL); + + if (dst->width > 0 && dst->height > 0) + return frame_copy_video(dst, src); + else if (dst->nb_samples > 0 && dst->channel_layout) + return frame_copy_audio(dst, src); + + return AVERROR(EINVAL); +} + +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + AVFrameSideData *sd = frame->side_data[i]; + if (sd->type == type) { + free_side_data(&frame->side_data[i]); + frame->side_data[i] = frame->side_data[frame->nb_side_data - 1]; + frame->nb_side_data--; + } + } +} + +const char *av_frame_side_data_name(enum AVFrameSideDataType type) +{ + switch(type) { + case AV_FRAME_DATA_PANSCAN: return "AVPanScan"; + case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions"; + case AV_FRAME_DATA_STEREO3D: return "Stereoscopic 3d metadata"; + case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding"; + case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure"; + case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain"; + case AV_FRAME_DATA_DISPLAYMATRIX: return "3x3 displaymatrix"; + case AV_FRAME_DATA_MOTION_VECTORS: return "Motion vectors"; + } + return NULL; +} +#endif diff --git a/libavutil/frame.h b/libavutil/frame.h new file mode 100644 index 0000000..27d7d33 --- /dev/null +++ b/libavutil/frame.h @@ -0,0 +1,703 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, + /** + * Recommmends skipping the specified number of samples. This is exported + * only if the "skip_manual" AVOption is set in libavcodec. + * This has the same format as AV_PKT_DATA_SKIP_SAMPLES. + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_FRAME_DATA_SKIP_SAMPLES, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; +} AVFrameSideData; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * Similarly fields that are marked as to be only accessed by + * av_opt_ptr() can be reordered. This allows 2 forks to add fields + * without breaking compatibility with each other. + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + +#if 0 + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; +#endif + + /** + * width and height of the video frame + */ + int width, height; + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + uint8_t *base[AV_NUM_DATA_POINTERS]; +#endif + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + */ + int64_t pkt_pts; + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + + /** + * for some private data of the user + */ + void *opaque; + + /** + * error + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int type; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int buffer_hints; + + /** + * Pan scan. + */ + attribute_deprecated + struct AVPanScan *pan_scan; +#endif + + /** + * reordered opaque 64bit (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + * @deprecated in favor of pkt_pts + */ + int64_t reordered_opaque; + +#if FF_API_AVFRAME_LAVC + /** + * @deprecated this field is unused + */ + attribute_deprecated void *hwaccel_picture_private; + + attribute_deprecated + struct AVCodecContext *owner; + attribute_deprecated + void *thread_opaque; + + /** + * log2 of the size of the block which a single vector in motion_val represents: + * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2) + */ + uint8_t motion_subsample_log2; +#endif + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + +#if 0 + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; +#endif + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * It must be accessed using av_frame_get_color_range() and + * av_frame_set_color_range(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * It must be accessed using av_frame_get_colorspace() and + * av_frame_set_colorspace(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * Code outside libavcodec should access this field using: + * av_frame_get_best_effort_timestamp(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_pos(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_duration(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * Code outside libavcodec should access this field using: + * av_frame_get_decode_error_flags(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 + + /** + * number of audio channels, only used for audio. + * Code outside libavcodec should access this field using: + * av_frame_get_channels(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. It must be accessed using av_frame_get_pkt_size() and + * av_frame_set_pkt_size(). + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; +} AVFrame; + +/** + * Accessors for some AVFrame fields. + * The position of these field in the structure is not part of the ABI, + * they should not be accessed directly outside libavcodec. + */ +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +int64_t av_frame_get_channel_layout (const AVFrame *frame); +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +int av_frame_get_channels (const AVFrame *frame); +void av_frame_set_channels (AVFrame *frame, int val); +int av_frame_get_sample_rate (const AVFrame *frame); +void av_frame_set_sample_rate (AVFrame *frame, int val); +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +int av_frame_get_decode_error_flags (const AVFrame *frame); +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +int av_frame_get_pkt_size(const AVFrame *frame); +void av_frame_set_pkt_size(AVFrame *frame, int val); +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everythnig contained in src to dst and reset src. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @param frame frame in which to store the new buffers. + * @param align required buffer size alignment + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/libavutil/hash.h b/libavutil/hash.h new file mode 100644 index 0000000..d4bcbf8 --- /dev/null +++ b/libavutil/hash.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * @note The context is not initialized, you must call av_hash_init(). + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param i index of the hash algorithm, starting from 0 + * @return a pointer to a static string or NULL if i is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size will currently return. + * + * You can use this if you absolutely want or need to use static allocation + * and are fine with not supporting hashes newly added to libavutil without + * recompilation. + * Note that you still need to check against av_hash_get_size, adding new hashes + * with larger sizes will not be considered an ABI change and should not cause + * your code to overflow a buffer. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The pointer passed to av_hash_final have space for at least this many bytes. + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); + +/** + * Finalize a hash context and compute the actual hash value. + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and compute the actual hash value. + * If size is smaller than the hash size, the hash is truncated; + * if size is larger, the buffer is padded with 0. + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a hex string. + * The string is always 0-terminated. + * If size is smaller than 2 * hash_size + 1, the hex string is truncated. + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a base64 string. + * The string is always 0-terminated. + * If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is + * truncated. + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context. + */ +void av_hash_freep(struct AVHashContext **ctx); + +#endif /* AVUTIL_HASH_H */ diff --git a/libavutil/hmac.h b/libavutil/hmac.h new file mode 100644 index 0000000..d36d4de --- /dev/null +++ b/libavutil/hmac.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224 = 10, + AV_HMAC_SHA256, + AV_HMAC_SHA384, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/libavutil/imgutils.h b/libavutil/imgutils.h new file mode 100644 index 0000000..2ec246a --- /dev/null +++ b/libavutil/imgutils.h @@ -0,0 +1,213 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with !src to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param[in] align the assumed linesize alignment + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/libavutil/integer.h b/libavutil/integer.h new file mode 100644 index 0000000..45f733c --- /dev/null +++ b/libavutil/integer.h @@ -0,0 +1,86 @@ +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * arbitrary precision integers + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_INTEGER_H +#define AVUTIL_INTEGER_H + +#include +#include "common.h" + +#define AV_INTEGER_SIZE 8 + +typedef struct AVInteger{ + uint16_t v[AV_INTEGER_SIZE]; +} AVInteger; + +AVInteger av_add_i(AVInteger a, AVInteger b) av_const; +AVInteger av_sub_i(AVInteger a, AVInteger b) av_const; + +/** + * Return the rounded-down value of the base 2 logarithm of the given + * AVInteger. This is simply the index of the most significant bit + * which is 1, or 0 if all bits are 0. + */ +int av_log2_i(AVInteger a) av_const; +AVInteger av_mul_i(AVInteger a, AVInteger b) av_const; + +/** + * Return 0 if a==b, 1 if a>b and -1 if a + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal API header + */ + +#ifndef AVUTIL_INTERNAL_H +#define AVUTIL_INTERNAL_H + +#if !defined(DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif + +#include +#include +#include +#include +#include "config.h" +#include "attributes.h" +#include "timer.h" +#include "cpu.h" +#include "dict.h" +#include "pixfmt.h" +#include "version.h" + +#if ARCH_X86 +# include "x86/emms.h" +#endif + +#ifndef emms_c +# define emms_c() +#endif + +#ifndef attribute_align_arg +#if ARCH_X86_32 && AV_GCC_VERSION_AT_LEAST(4,2) +# define attribute_align_arg __attribute__((force_align_arg_pointer)) +#else +# define attribute_align_arg +#endif +#endif + +#if defined(_MSC_VER) && CONFIG_SHARED +# define av_export __declspec(dllimport) +#else +# define av_export +#endif + +#if HAVE_PRAGMA_DEPRECATED +# if defined(__ICL) || defined (__INTEL_COMPILER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# elif defined(_MSC_VER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# else +# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") +# endif +#else +# define FF_DISABLE_DEPRECATION_WARNINGS +# define FF_ENABLE_DEPRECATION_WARNINGS +#endif + +#ifndef INT_BIT +# define INT_BIT (CHAR_BIT * sizeof(int)) +#endif + +#define FF_MEMORY_POISON 0x2a + +#define MAKE_ACCESSORS(str, name, type, field) \ + type av_##name##_get_##field(const str *s) { return s->field; } \ + void av_##name##_set_##field(str *s, type v) { s->field = v; } + +// Some broken preprocessors need a second expansion +// to be forced to tokenize __VA_ARGS__ +#define E1(x) x + +/* Check if the hard coded offset of a struct member still matches reality. + * Induce a compilation failure if not. + */ +#define AV_CHECK_OFFSET(s, m, o) struct check_##o { \ + int x_##o[offsetof(s, m) == o? 1: -1]; \ + } + +#define LOCAL_ALIGNED_A(a, t, v, s, o, ...) \ + uint8_t la_##v[sizeof(t s o) + (a)]; \ + t (*v) o = (void *)FFALIGN((uintptr_t)la_##v, a) + +#define LOCAL_ALIGNED_D(a, t, v, s, o, ...) \ + DECLARE_ALIGNED(a, t, la_##v) s o; \ + t (*v) o = la_##v + +#define LOCAL_ALIGNED(a, t, v, ...) E1(LOCAL_ALIGNED_A(a, t, v, __VA_ARGS__,,)) + +#if HAVE_LOCAL_ALIGNED_8 +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_D(8, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_8(t, v, ...) LOCAL_ALIGNED(8, t, v, __VA_ARGS__) +#endif + +#if HAVE_LOCAL_ALIGNED_16 +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_D(16, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_16(t, v, ...) LOCAL_ALIGNED(16, t, v, __VA_ARGS__) +#endif + +#if HAVE_LOCAL_ALIGNED_32 +# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_32(t, v, ...) LOCAL_ALIGNED(32, t, v, __VA_ARGS__) +#endif + +#define FF_ALLOC_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_malloc(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_mallocz(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOC_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_malloc_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_mallocz_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#include "libm.h" + +#if defined(_MSC_VER) +#pragma comment(linker, "/include:"EXTERN_PREFIX"avpriv_strtod") +#pragma comment(linker, "/include:"EXTERN_PREFIX"avpriv_snprintf") +#endif + +/** + * Return NULL if CONFIG_SMALL is true, otherwise the argument + * without modification. Used to disable the definition of strings + * (for example AVCodec long_names). + */ +#if CONFIG_SMALL +# define NULL_IF_CONFIG_SMALL(x) NULL +#else +# define NULL_IF_CONFIG_SMALL(x) x +#endif + +/** + * Define a function with only the non-default version specified. + * + * On systems with ELF shared libraries, all symbols exported from + * FFmpeg libraries are tagged with the name and major version of the + * library to which they belong. If a function is moved from one + * library to another, a wrapper must be retained in the original + * location to preserve binary compatibility. + * + * Functions defined with this macro will never be used to resolve + * symbols by the build-time linker. + * + * @param type return type of function + * @param name name of function + * @param args argument list of function + * @param ver version tag to assign function + */ +#if HAVE_SYMVER_ASM_LABEL +# define FF_SYMVER(type, name, args, ver) \ + type ff_##name args __asm__ (EXTERN_PREFIX #name "@" ver); \ + type ff_##name args +#elif HAVE_SYMVER_GNU_ASM +# define FF_SYMVER(type, name, args, ver) \ + __asm__ (".symver ff_" #name "," EXTERN_PREFIX #name "@" ver); \ + type ff_##name args; \ + type ff_##name args +#endif + +/** + * Return NULL if a threading library has not been enabled. + * Used to disable threading functions in AVCodec definitions + * when not needed. + */ +#if HAVE_THREADS +# define ONLY_IF_THREADS_ENABLED(x) x +#else +# define ONLY_IF_THREADS_ENABLED(x) NULL +#endif + +/** + * Log a generic warning message about a missing feature. + * + * @param[in] avc a pointer to an arbitrary struct of which the first + * field is a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +#ifdef USE_AV_LOG +void avpriv_report_missing_feature(void *avc, + const char *msg, ...) av_printf_format(2, 3); +#else +#define avpriv_report_missing_feature(avc, msg, ...) do { } while (0) +#endif +/** + * Log a generic warning message about a missing feature. + * Additionally request that a sample showcasing the feature be uploaded. + * + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_request_sample(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +#if HAVE_LIBC_MSVCRT +#define avpriv_open ff_open +#define PTRDIFF_SPECIFIER "Id" +#define SIZE_SPECIFIER "Iu" +#else +#define PTRDIFF_SPECIFIER "td" +#define SIZE_SPECIFIER "zu" +#endif + +/** + * A wrapper for open() setting O_CLOEXEC. + */ +int avpriv_open(const char *filename, int flags, ...); + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); + +#if FF_API_GET_CHANNEL_LAYOUT_COMPAT +uint64_t ff_get_channel_layout(const char *name, int compat); +#endif + +#endif /* AVUTIL_INTERNAL_H */ diff --git a/libavutil/intfloat.h b/libavutil/intfloat.h new file mode 100644 index 0000000..fe3d7ec --- /dev/null +++ b/libavutil/intfloat.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/libavutil/intmath.h b/libavutil/intmath.h new file mode 100644 index 0000000..308c776 --- /dev/null +++ b/libavutil/intmath.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTMATH_H +#define AVUTIL_INTMATH_H + +#include + +#include "config.h" +#include "attributes.h" + +#if ARCH_ARM +# include "arm/intmath.h" +#endif + +/** + * @addtogroup lavu_internal + * @{ + */ + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3,4) +#ifndef ff_log2 +# define ff_log2(x) (31 - __builtin_clz((x)|1)) +# ifndef ff_log2_16bit +# define ff_log2_16bit av_log2 +# endif +#endif /* ff_log2 */ +#elif defined( __INTEL_COMPILER ) +#ifndef ff_log2 +# define ff_log2(x) (_bit_scan_reverse(x|1)) +# ifndef ff_log2_16bit +# define ff_log2_16bit av_log2 +# endif +#endif /* ff_log2 */ +#endif +#endif /* AV_GCC_VERSION_AT_LEAST(3,4) */ + +extern const uint8_t ff_log2_tab[256]; + +#ifndef ff_log2 +#define ff_log2 ff_log2_c +#if !defined( _MSC_VER ) +static av_always_inline av_const int ff_log2_c(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#else +static av_always_inline av_const int ff_log2_c(unsigned int v) +{ + unsigned long n; + _BitScanReverse(&n, v|1); + return n; +} +#define ff_log2_16bit av_log2 +#endif +#endif + +#ifndef ff_log2_16bit +#define ff_log2_16bit ff_log2_16bit_c +static av_always_inline av_const int ff_log2_16bit_c(unsigned int v) +{ + int n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#define av_log2 ff_log2 +#define av_log2_16bit ff_log2_16bit + +/** + * @} + */ + +/** + * @addtogroup lavu_math + * @{ + */ + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3,4) +#ifndef ff_ctz +#define ff_ctz(v) __builtin_ctz(v) +#endif +#elif defined( __INTEL_COMPILER ) +#ifndef ff_ctz +#define ff_ctz(v) _bit_scan_forward(v) +#endif +#endif +#endif + +#ifndef ff_ctz +#define ff_ctz ff_ctz_c +#if !defined( _MSC_VER ) +static av_always_inline av_const int ff_ctz_c(int v) +{ + int c; + + if (v & 0x1) + return 0; + + c = 1; + if (!(v & 0xffff)) { + v >>= 16; + c += 16; + } + if (!(v & 0xff)) { + v >>= 8; + c += 8; + } + if (!(v & 0xf)) { + v >>= 4; + c += 4; + } + if (!(v & 0x3)) { + v >>= 2; + c += 2; + } + c -= v & 0x1; + + return c; +} +#else +static av_always_inline av_const int ff_ctz_c( int v ) +{ + unsigned long c; + _BitScanForward(&c, v); + return c; +} +#endif +#endif + +/** + * Trailing zero bit count. + * + * @param v input value. If v is 0, the result is undefined. + * @return the number of trailing 0-bits + */ +int av_ctz(int v); + +/** + * @} + */ +#endif /* AVUTIL_INTMATH_H */ diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h new file mode 100644 index 0000000..51fbe30 --- /dev/null +++ b/libavutil/intreadwrite.h @@ -0,0 +1,629 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(__DECC) + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/libavutil/lfg.h b/libavutil/lfg.h new file mode 100644 index 0000000..ec90562 --- /dev/null +++ b/libavutil/lfg.h @@ -0,0 +1,62 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/libavutil/libm.h b/libavutil/libm.h new file mode 100644 index 0000000..6c17b28 --- /dev/null +++ b/libavutil/libm.h @@ -0,0 +1,189 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Replacements for frequently missing libm functions + */ + +#ifndef AVUTIL_LIBM_H +#define AVUTIL_LIBM_H + +#include +#include "config.h" +#include "attributes.h" +#include "intfloat.h" + +#if HAVE_MIPSFPU && HAVE_INLINE_ASM +#include "libavutil/mips/libm_mips.h" +#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM*/ + +#if !HAVE_ATANF +#undef atanf +#define atanf(x) ((float)atan(x)) +#endif + +#if !HAVE_ATAN2F +#undef atan2f +#define atan2f(y, x) ((float)atan2(y, x)) +#endif + +#if !HAVE_POWF +#undef powf +#define powf(x, y) ((float)pow(x, y)) +#endif + +#if !HAVE_CBRT +static av_always_inline double cbrt(double x) +{ + return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0); +} +#endif + +#if !HAVE_CBRTF +static av_always_inline float cbrtf(float x) +{ + return x < 0 ? -powf(-x, 1.0 / 3.0) : powf(x, 1.0 / 3.0); +} +#endif + +#if !HAVE_COSF +#undef cosf +#define cosf(x) ((float)cos(x)) +#endif + +#if !HAVE_EXPF +#undef expf +#define expf(x) ((float)exp(x)) +#endif + +#if !HAVE_EXP2 +#undef exp2 +#define exp2(x) exp((x) * 0.693147180559945) +#endif /* HAVE_EXP2 */ + +#if !HAVE_EXP2F +#undef exp2f +#define exp2f(x) ((float)exp2(x)) +#endif /* HAVE_EXP2F */ + +#if !HAVE_ISINF +static av_always_inline av_const int isinf(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return !(v & 0x007fffff); +} +#endif /* HAVE_ISINF */ + +#if !HAVE_ISNAN +static av_always_inline av_const int isnan(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return v & 0x007fffff; +} +#endif /* HAVE_ISNAN */ + +#if !HAVE_LDEXPF +#undef ldexpf +#define ldexpf(x, exp) ((float)ldexp(x, exp)) +#endif + +#if !HAVE_LLRINT +#undef llrint +#define llrint(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LLRINTF +#undef llrintf +#define llrintf(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LOG2 +#undef log2 +#define log2(x) (log(x) * 1.44269504088896340736) +#endif /* HAVE_LOG2 */ + +#if !HAVE_LOG2F +#undef log2f +#define log2f(x) ((float)log2(x)) +#endif /* HAVE_LOG2F */ + +#if !HAVE_LOG10F +#undef log10f +#define log10f(x) ((float)log10(x)) +#endif + +#if !HAVE_SINF +#undef sinf +#define sinf(x) ((float)sin(x)) +#endif + +#if !HAVE_RINT +static inline double rint(double x) +{ + return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_RINT */ + +#if !HAVE_LRINT +static av_always_inline av_const long int lrint(double x) +{ + return rint(x); +} +#endif /* HAVE_LRINT */ + +#if !HAVE_LRINTF +static av_always_inline av_const long int lrintf(float x) +{ + return (int)(rint(x)); +} +#endif /* HAVE_LRINTF */ + +#if !HAVE_ROUND +static av_always_inline av_const double round(double x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUND */ + +#if !HAVE_ROUNDF +static av_always_inline av_const float roundf(float x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUNDF */ + +#if !HAVE_TRUNC +static av_always_inline av_const double trunc(double x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNC */ + +#if !HAVE_TRUNCF +static av_always_inline av_const float truncf(float x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNCF */ + +#endif /* AVUTIL_LIBM_H */ diff --git a/libavutil/lls.h b/libavutil/lls.h new file mode 100644 index 0000000..5635b5b --- /dev/null +++ b/libavutil/lls.h @@ -0,0 +1,64 @@ +/* + * linear least squares model + * + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LLS_H +#define AVUTIL_LLS_H + +#include "common.h" +#include "mem.h" +#include "version.h" + +#define MAX_VARS 32 +#define MAX_VARS_ALIGN FFALIGN(MAX_VARS+1,4) + +//FIXME avoid direct access to LLSModel from outside + +/** + * Linear least squares model. + */ +typedef struct LLSModel { + DECLARE_ALIGNED(32, double, covariance[MAX_VARS_ALIGN][MAX_VARS_ALIGN]); + DECLARE_ALIGNED(32, double, coeff[MAX_VARS][MAX_VARS]); + double variance[MAX_VARS]; + int indep_count; + /** + * Take the outer-product of var[] with itself, and add to the covariance matrix. + * @param m this context + * @param var training samples, starting with the value to be predicted + * 32-byte aligned, and any padding elements must be initialized + * (i.e not denormal/nan). + */ + void (*update_lls)(struct LLSModel *m, const double *var); + /** + * Inner product of var[] and the LPC coefs. + * @param m this context + * @param var training samples, excluding the value to be predicted. unaligned. + * @param order lpc order + */ + double (*evaluate_lls)(struct LLSModel *m, const double *var, int order); +} LLSModel; + +void avpriv_init_lls(LLSModel *m, int indep_count); +void ff_init_lls_x86(LLSModel *m); +void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order); + +#endif /* AVUTIL_LLS_H */ diff --git a/libavutil/log.h b/libavutil/log.h new file mode 100644 index 0000000..3a28eec --- /dev/null +++ b/libavutil/log.h @@ -0,0 +1,353 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOG_H +#define AVUTIL_LOG_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB, ///< not part of ABI/API +}AVClassCategory; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * a pointer to the first option specified in the class if any or NULL + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added without requiring major + * version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where log_level_offset is stored. + * 0 means there is no such variable + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an av_log() implementation + * could then leverage to display the parent context. + * The offset can be NULL. + */ + int parent_log_context_offset; + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Return an AVClass corresponding to the next potential + * AVOptions-enabled child. + * + * The difference between child_next and this is that + * child_next iterates over _already existing_ objects, while + * child_class_next iterates over _all possible_ children. + */ + const struct AVClass* (*child_class_next)(const struct AVClass *prev); + + /** + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) + */ + AVClassCategory category; + + /** + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + * available since version (52.12) + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) (x << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +#ifdef USE_AV_LOG +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); +#else +#define av_log(avcl, level, fmt, ...) do { } while (0) +#endif + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formated line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * av_dlog macros + * Useful to print debug messages that shouldn't get compiled in normally. + */ + +#ifdef DEBUG +# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/libavutil/log2_tab.c b/libavutil/log2_tab.c new file mode 100644 index 0000000..0dbf07d --- /dev/null +++ b/libavutil/log2_tab.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const uint8_t ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; diff --git a/libavutil/lzo.h b/libavutil/lzo.h new file mode 100644 index 0000000..c034039 --- /dev/null +++ b/libavutil/lzo.h @@ -0,0 +1,66 @@ +/* + * LZO 1x decompression + * copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LZO_H +#define AVUTIL_LZO_H + +/** + * @defgroup lavu_lzo LZO + * @ingroup lavu_crypto + * + * @{ + */ + +#include + +/** @name Error flags returned by av_lzo1x_decode + * @{ */ +/// end of the input buffer reached before decoding finished +#define AV_LZO_INPUT_DEPLETED 1 +/// decoded data did not fit into output buffer +#define AV_LZO_OUTPUT_FULL 2 +/// a reference to previously decoded data was wrong +#define AV_LZO_INVALID_BACKPTR 4 +/// a non-specific error in the compressed bitstream +#define AV_LZO_ERROR 8 +/** @} */ + +#define AV_LZO_INPUT_PADDING 8 +#define AV_LZO_OUTPUT_PADDING 12 + +/** + * @brief Decodes LZO 1x compressed data. + * @param out output buffer + * @param outlen size of output buffer, number of bytes left are returned here + * @param in input buffer + * @param inlen size of input buffer, number of bytes left are returned here + * @return 0 on success, otherwise a combination of the error flags above + * + * Make sure all buffers are appropriately padded, in must provide + * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. + */ +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); + +/** + * @} + */ + +#endif /* AVUTIL_LZO_H */ diff --git a/libavutil/macros.h b/libavutil/macros.h new file mode 100644 index 0000000..4465323 --- /dev/null +++ b/libavutil/macros.h @@ -0,0 +1,48 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#endif /* AVUTIL_MACROS_H */ diff --git a/libavutil/mathematics.h b/libavutil/mathematics.h new file mode 100644 index 0000000..ac94488 --- /dev/null +++ b/libavutil/mathematics.h @@ -0,0 +1,164 @@ +/* + * copyright (c) 2005-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include +#include +#include "attributes.h" +#include "rational.h" +#include "intfloat.h" + +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif +#ifndef M_LOG2_10 +#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ +#endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif +#ifndef NAN +#define NAN av_int2float(0x7fc00000) +#endif +#ifndef INFINITY +#define INFINITY av_int2float(0x7f800000) +#endif + +/** + * @addtogroup lavu_math + * @{ + */ + + +enum AVRounding { + AV_ROUND_ZERO = 0, ///< Round toward zero. + AV_ROUND_INF = 1, ///< Round away from zero. + AV_ROUND_DOWN = 2, ///< Round toward -infinity. + AV_ROUND_UP = 3, ///< Round toward +infinity. + AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE +}; + +/** + * Return the greatest common divisor of a and b. + * If both a and b are 0 or either or both are <0 then behavior is + * undefined. + */ +int64_t av_const av_gcd(int64_t a, int64_t b); + +/** + * Rescale a 64-bit integer with rounding to nearest. + * A simple a*b/c isn't possible as it can overflow. + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; + +/** + * Rescale a 64-bit integer with specified rounding. + * A simple a*b/c isn't possible as it can overflow. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers. + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding) av_const; + +/** + * Compare 2 timestamps each in its own timebases. + * The result of the function is undefined if one of the timestamps + * is outside the int64_t range when represented in the others timebase. + * @return -1 if ts_a is before ts_b, 1 if ts_a is after ts_b or 0 if they represent the same position + */ +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); + +/** + * Compare 2 integers modulo mod. + * That is we compare integers a and b for which only the least + * significant log2(mod) bits are known. + * + * @param mod must be a power of 2 + * @return a negative value if a is smaller than b + * a positive value if a is greater than b + * 0 if a equals b + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * @param in_ts Input timestamp + * @param in_tb Input timebase + * @param fs_tb Duration and *last timebase + * @param duration duration till the next call + * @param out_tb Output timebase + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatly added that + * no accumulation of rounding errors occurs. + * + * @param ts Input timestamp + * @param ts_tb Input timestamp timebase + * @param inc value to add to ts + * @param inc_tb inc timebase + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + + + /** + * @} + */ + +#endif /* AVUTIL_MATHEMATICS_H */ diff --git a/libavutil/md5.c b/libavutil/md5.c new file mode 100644 index 0000000..876bd55 --- /dev/null +++ b/libavutil/md5.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2006 Michael Niedermayer (michaelni@gmx.at) + * Copyright (C) 2003-2005 by Christopher R. Hertel (crh@ubiqx.mn.org) + * + * References: + * IETF RFC 1321: The MD5 Message-Digest Algorithm + * Ron Rivest. IETF, April, 1992 + * + * based on http://ubiqx.org/libcifs/source/Auth/MD5.c + * from Christopher R. Hertel (crh@ubiqx.mn.org) + * Simplified, cleaned and IMO redundant comments removed by michael. + * + * If you use gcc, then version 4.1 or later and -fomit-frame-pointer is + * strongly recommended. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "bswap.h" +#include "intreadwrite.h" +#include "md5.h" +#include "mem.h" + +typedef struct AVMD5{ + uint64_t len; + uint8_t block[64]; + uint32_t ABCD[4]; +} AVMD5; + +const int av_md5_size = sizeof(AVMD5); + +struct AVMD5 *av_md5_alloc(void) +{ + return av_mallocz(sizeof(struct AVMD5)); +} + +static const uint8_t S[4][4] = { + { 7, 12, 17, 22 }, /* round 1 */ + { 5, 9, 14, 20 }, /* round 2 */ + { 4, 11, 16, 23 }, /* round 3 */ + { 6, 10, 15, 21 } /* round 4 */ +}; + +static const uint32_t T[64] = { // T[i]= fabs(sin(i+1)<<32) + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* round 1 */ + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* round 2 */ + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* round 3 */ + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* round 4 */ + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +#define CORE(i, a, b, c, d) do { \ + t = S[i >> 4][i & 3]; \ + a += T[i]; \ + \ + if (i < 32) { \ + if (i < 16) a += (d ^ (b & (c ^ d))) + X[ i & 15]; \ + else a += ((d & b) | (~d & c)) + X[(1 + 5*i) & 15]; \ + } else { \ + if (i < 48) a += (b ^ c ^ d) + X[(5 + 3*i) & 15]; \ + else a += (c ^ (b | ~d)) + X[( 7*i) & 15]; \ + } \ + a = b + (a << t | a >> (32 - t)); \ + } while (0) + +static void body(uint32_t ABCD[4], uint32_t *src, int nblocks) +{ + int i av_unused; + int n; + uint32_t a, b, c, d, t, *X; + + for (n = 0; n < nblocks; n++) { + a = ABCD[3]; + b = ABCD[2]; + c = ABCD[1]; + d = ABCD[0]; + + X = src + n * 16; + +#if HAVE_BIGENDIAN + for (i = 0; i < 16; i++) + X[i] = av_bswap32(X[i]); +#endif + +#if CONFIG_SMALL + for (i = 0; i < 64; i++) { + CORE(i, a, b, c, d); + t = d; + d = c; + c = b; + b = a; + a = t; + } +#else +#define CORE2(i) \ + CORE( i, a,b,c,d); CORE((i+1),d,a,b,c); \ + CORE((i+2),c,d,a,b); CORE((i+3),b,c,d,a) +#define CORE4(i) CORE2(i); CORE2((i+4)); CORE2((i+8)); CORE2((i+12)) + CORE4(0); CORE4(16); CORE4(32); CORE4(48); +#endif + + ABCD[0] += d; + ABCD[1] += c; + ABCD[2] += b; + ABCD[3] += a; + } +} + +void av_md5_init(AVMD5 *ctx) +{ + ctx->len = 0; + + ctx->ABCD[0] = 0x10325476; + ctx->ABCD[1] = 0x98badcfe; + ctx->ABCD[2] = 0xefcdab89; + ctx->ABCD[3] = 0x67452301; +} + +void av_md5_update(AVMD5 *ctx, const uint8_t *src, int len) +{ + const uint8_t *end; + int j; + + j = ctx->len & 63; + ctx->len += len; + + if (j) { + int cnt = FFMIN(len, 64 - j); + memcpy(ctx->block + j, src, cnt); + src += cnt; + len -= cnt; + if (j + cnt < 64) + return; + body(ctx->ABCD, (uint32_t *)ctx->block, 1); + } + + end = src + (len & ~63); + if (HAVE_BIGENDIAN || (!HAVE_FAST_UNALIGNED && ((intptr_t)src & 3))) { + while (src < end) { + memcpy(ctx->block, src, 64); + body(ctx->ABCD, (uint32_t *) ctx->block, 1); + src += 64; + } + } else { + int nblocks = len / 64; + body(ctx->ABCD, (uint32_t *)src, nblocks); + src = end; + } + len &= 63; + if (len > 0) + memcpy(ctx->block, src, len); +} + +void av_md5_final(AVMD5 *ctx, uint8_t *dst) +{ + int i; + uint64_t finalcount = av_le2ne64(ctx->len << 3); + + av_md5_update(ctx, "\200", 1); + while ((ctx->len & 63) != 56) + av_md5_update(ctx, "", 1); + + av_md5_update(ctx, (uint8_t *)&finalcount, 8); + + for (i = 0; i < 4; i++) + AV_WL32(dst + 4*i, ctx->ABCD[3 - i]); +} + +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len) +{ + AVMD5 ctx; + + av_md5_init(&ctx); + av_md5_update(&ctx, src, len); + av_md5_final(&ctx, dst); +} + +#ifdef TEST +#include + +static void print_md5(uint8_t *md5) +{ + int i; + for (i = 0; i < 16; i++) + printf("%02x", md5[i]); + printf("\n"); +} + +int main(void){ + uint8_t md5val[16]; + int i; + volatile uint8_t in[1000]; // volatile to workaround http://llvm.org/bugs/show_bug.cgi?id=20849 + // FIXME remove volatile once it has been fixed and all fate clients are updated + + for (i = 0; i < 1000; i++) + in[i] = i * i; + av_md5_sum(md5val, in, 1000); print_md5(md5val); + av_md5_sum(md5val, in, 63); print_md5(md5val); + av_md5_sum(md5val, in, 64); print_md5(md5val); + av_md5_sum(md5val, in, 65); print_md5(md5val); + for (i = 0; i < 1000; i++) + in[i] = i % 127; + av_md5_sum(md5val, in, 999); print_md5(md5val); + + return 0; +} +#endif diff --git a/libavutil/md5.h b/libavutil/md5.h new file mode 100644 index 0000000..79702c8 --- /dev/null +++ b/libavutil/md5.h @@ -0,0 +1,81 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/libavutil/mem.c b/libavutil/mem.c new file mode 100644 index 0000000..b47b2e6 --- /dev/null +++ b/libavutil/mem.c @@ -0,0 +1,571 @@ +/* + * default memory allocator for libavutil + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * default memory allocator for libavutil + */ + +#define _XOPEN_SOURCE 600 + +#include "config.h" + +#include +#include +#include +#include +#if HAVE_MALLOC_H +#include +#endif + +#include "avassert.h" +#include "avutil.h" +#include "common.h" +#include "dynarray.h" +#include "intreadwrite.h" +#include "mem.h" + +//#define USE_MEM_STATS + +#ifdef USE_MEM_STATS +#include +static int mem_cur, mem_max; +static int block_cur, block_max; +#endif + +#ifdef MALLOC_PREFIX + +#define malloc AV_JOIN(MALLOC_PREFIX, malloc) +#define memalign AV_JOIN(MALLOC_PREFIX, memalign) +#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) +#define realloc AV_JOIN(MALLOC_PREFIX, realloc) +#define free AV_JOIN(MALLOC_PREFIX, free) + +void *malloc(size_t size); +void *memalign(size_t align, size_t size); +int posix_memalign(void **ptr, size_t align, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +#endif /* MALLOC_PREFIX */ + +#define ALIGN (HAVE_AVX ? 32 : 16) + +/* NOTE: if you want to override these functions with your own + * implementations (not recommended) you have to link libav* as + * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. + * Note that this will cost performance. */ + +static size_t max_alloc_size= INT_MAX; + +void av_max_alloc(size_t max){ + max_alloc_size = max; +} + +void *av_malloc(size_t size) +{ + void *ptr = NULL; +#if CONFIG_MEMALIGN_HACK + long diff; +#endif + + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if CONFIG_MEMALIGN_HACK + ptr = malloc(size + ALIGN); + if (!ptr) + return ptr; + diff = ((~(long)ptr)&(ALIGN - 1)) + 1; + ptr = (char *)ptr + diff; + ((char *)ptr)[-1] = diff; +#elif HAVE_POSIX_MEMALIGN + if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation + if (posix_memalign(&ptr, ALIGN, size)) + ptr = NULL; +#elif HAVE_ALIGNED_MALLOC + ptr = _aligned_malloc(size, ALIGN); +#elif HAVE_MEMALIGN +#ifndef __DJGPP__ + ptr = memalign(ALIGN, size); +#else + ptr = memalign(size, ALIGN); +#endif + /* Why 64? + * Indeed, we should align it: + * on 4 for 386 + * on 16 for 486 + * on 32 for 586, PPro - K6-III + * on 64 for K7 (maybe for P3 too). + * Because L1 and L2 caches are aligned on those values. + * But I don't want to code such logic here! + */ + /* Why 32? + * For AVX ASM. SSE / NEON needs only 16. + * Why not larger? Because I did not see a difference in benchmarks ... + */ + /* benchmarks with P3 + * memalign(64) + 1 3071, 3051, 3032 + * memalign(64) + 2 3051, 3032, 3041 + * memalign(64) + 4 2911, 2896, 2915 + * memalign(64) + 8 2545, 2554, 2550 + * memalign(64) + 16 2543, 2572, 2563 + * memalign(64) + 32 2546, 2545, 2571 + * memalign(64) + 64 2570, 2533, 2558 + * + * BTW, malloc seems to do 8-byte alignment by default here. + */ +#else + ptr = malloc(size); +#ifdef USE_MEM_STATS + printf("malloc(%ld) -> %p\n", size, ptr); + if (ptr) { + mem_cur += malloc_usable_size(ptr); + if (mem_cur > mem_max) { + mem_max = mem_cur; + printf("mem_max=%d\n", mem_max); + } + if (++block_cur > block_max) { + block_max = block_cur; + printf("block_max=%d\n", block_max); + } + } +#endif +#endif + if(!ptr && !size) { + size = 1; + ptr= av_malloc(1); + } +#if CONFIG_MEMORY_POISONING + if (ptr) + memset(ptr, FF_MEMORY_POISON, size); +#endif + return ptr; +} + +void *av_realloc(void *ptr, size_t size) +{ +#if CONFIG_MEMALIGN_HACK + int diff; +#endif + + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if CONFIG_MEMALIGN_HACK + //FIXME this isn't aligned correctly, though it probably isn't needed + if (!ptr) + return av_malloc(size); + diff = ((char *)ptr)[-1]; + av_assert0(diff>0 && diff<=ALIGN); + ptr = realloc((char *)ptr - diff, size + diff); + if (ptr) + ptr = (char *)ptr + diff; + return ptr; +#elif HAVE_ALIGNED_MALLOC + return _aligned_realloc(ptr, size + !size, ALIGN); +#else +#ifdef USE_MEM_STATS + if (ptr) { + mem_cur -= malloc_usable_size(ptr); + block_cur--; + } + printf("realloc(%p, %ld)\n", ptr, size); + ptr = realloc(ptr, size + !size); + if (ptr) { + mem_cur += malloc_usable_size(ptr); + if (mem_cur > mem_max) { + mem_max = mem_cur; + printf("mem_max=%d\n", mem_max); + } + if (++block_cur > block_max) { + block_max = block_cur; + printf("block_max=%d\n", block_max); + } + } + return ptr; +#else + return realloc(ptr, size + !size); +#endif +#endif +} + +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) +{ + size_t size; + void *r; + + if (av_size_mult(elsize, nelem, &size)) { + av_free(ptr); + return NULL; + } + r = av_realloc(ptr, size); + if (!r && size) + av_free(ptr); + return r; +} + +int av_reallocp(void *ptr, size_t size) +{ + void **ptrptr = ptr; + void *ret; + + if (!size) { + av_freep(ptr); + return 0; + } + ret = av_realloc(*ptrptr, size); + + if (!ret) { + av_freep(ptr); + return AVERROR(ENOMEM); + } + + *ptrptr = ret; + return 0; +} + +void *av_realloc_array(void *ptr, size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_realloc(ptr, nmemb * size); +} + +int av_reallocp_array(void *ptr, size_t nmemb, size_t size) +{ + void **ptrptr = ptr; + *ptrptr = av_realloc_f(*ptrptr, nmemb, size); + if (!*ptrptr && nmemb && size) + return AVERROR(ENOMEM); + return 0; +} + +void av_free(void *ptr) +{ +#if CONFIG_MEMALIGN_HACK + if (ptr) { + int v= ((char *)ptr)[-1]; + av_assert0(v>0 && v<=ALIGN); + free((char *)ptr - v); + } +#elif HAVE_ALIGNED_MALLOC + _aligned_free(ptr); +#else +#ifdef USE_MEM_STATS + if (ptr) { + printf("free(%p)\n", ptr); + mem_cur -= malloc_usable_size(ptr); + block_cur--; + } +#endif + free(ptr); +#endif +} + +void av_freep(void *arg) +{ + void **ptr = (void **)arg; + av_free(*ptr); + *ptr = NULL; +} + +void *av_mallocz(size_t size) +{ + void *ptr = av_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +#ifdef USE_FULL +void *av_calloc(size_t nmemb, size_t size) +{ + if (size <= 0 || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +char *av_strdup(const char *s) +{ + char *ptr = NULL; + if (s) { + int len = strlen(s) + 1; + ptr = av_realloc(NULL, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +char *av_strndup(const char *s, size_t len) +{ + char *ret = NULL, *end; + + if (!s) + return NULL; + + end = memchr(s, 0, len); + if (end) + len = end - s; + + ret = av_realloc(NULL, len + 1); + if (!ret) + return NULL; + + memcpy(ret, s, len); + ret[len] = 0; + return ret; +} + +void *av_memdup(const void *p, size_t size) +{ + void *ptr = NULL; + if (p) { + ptr = av_malloc(size); + if (ptr) + memcpy(ptr, p, size); + } + return ptr; +} + +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab = *(void ***)tab_ptr; + + AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + *(void ***)tab_ptr = tab; + }, { + return AVERROR(ENOMEM); + }); + return 0; +} + +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab = *(void ***)tab_ptr; + + AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + *(void ***)tab_ptr = tab; + }, { + *nb_ptr = 0; + av_freep(tab_ptr); + }); +} + +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data) +{ + uint8_t *tab_elem_data = NULL; + + AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { + tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; + if (elem_data) + memcpy(tab_elem_data, elem_data, elem_size); + else if (CONFIG_MEMORY_POISONING) + memset(tab_elem_data, FF_MEMORY_POISON, elem_size); + }, { + av_freep(tab_ptr); + *nb_ptr = 0; + }); + return tab_elem_data; +} + +static void fill16(uint8_t *dst, int len) +{ + uint32_t v = AV_RN16(dst - 2); + + v |= v << 16; + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-2]; + dst++; + } +} + +static void fill24(uint8_t *dst, int len) +{ +#if HAVE_BIGENDIAN + uint32_t v = AV_RB24(dst - 3); + uint32_t a = v << 8 | v >> 16; + uint32_t b = v << 16 | v >> 8; + uint32_t c = v << 24 | v; +#else + uint32_t v = AV_RL24(dst - 3); + uint32_t a = v | v << 24; + uint32_t b = v >> 8 | v << 16; + uint32_t c = v >> 16 | v << 8; +#endif + + while (len >= 12) { + AV_WN32(dst, a); + AV_WN32(dst + 4, b); + AV_WN32(dst + 8, c); + dst += 12; + len -= 12; + } + + if (len >= 4) { + AV_WN32(dst, a); + dst += 4; + len -= 4; + } + + if (len >= 4) { + AV_WN32(dst, b); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-3]; + dst++; + } +} + +static void fill32(uint8_t *dst, int len) +{ + uint32_t v = AV_RN32(dst - 4); + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-4]; + dst++; + } +} + +void av_memcpy_backptr(uint8_t *dst, int back, int cnt) +{ + const uint8_t *src = &dst[-back]; + if (!back) + return; + + if (back == 1) { + memset(dst, *src, cnt); + } else if (back == 2) { + fill16(dst, cnt); + } else if (back == 3) { + fill24(dst, cnt); + } else if (back == 4) { + fill32(dst, cnt); + } else { + if (cnt >= 16) { + int blocklen = back; + while (cnt > blocklen) { + memcpy(dst, src, blocklen); + dst += blocklen; + cnt -= blocklen; + blocklen <<= 1; + } + memcpy(dst, src, cnt); + return; + } + if (cnt >= 8) { + AV_COPY32U(dst, src); + AV_COPY32U(dst + 4, src + 4); + src += 8; + dst += 8; + cnt -= 8; + } + if (cnt >= 4) { + AV_COPY32U(dst, src); + src += 4; + dst += 4; + cnt -= 4; + } + if (cnt >= 2) { + AV_COPY16U(dst, src); + src += 2; + dst += 2; + cnt -= 2; + } + if (cnt) + *dst = *src; + } +} + +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) +{ + if (min_size < *size) + return ptr; + + min_size = FFMAX(17 * min_size / 16 + 32, min_size); + + ptr = av_realloc(ptr, min_size); + /* we could set this to the unmodified min_size but this is safer + * if the user lost the ptr and uses NULL now + */ + if (!ptr) + min_size = 0; + + *size = min_size; + + return ptr; +} +#endif + +static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc) +{ + void **p = ptr; + if (min_size < *size) + return 0; + min_size = FFMAX(17 * min_size / 16 + 32, min_size); + av_free(*p); + *p = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size); + if (!*p) + min_size = 0; + *size = min_size; + return 1; +} + +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) +{ + ff_fast_malloc(ptr, size, min_size, 0); +} + +void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} diff --git a/libavutil/mem.h b/libavutil/mem.h new file mode 100644 index 0000000..37f3c1f --- /dev/null +++ b/libavutil/mem.h @@ -0,0 +1,379 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include +#include + +#include "attributes.h" +#include "error.h" +#include "avutil.h" + +/** + * @addtogroup lavu_mem + * @{ + */ + + +#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v +#elif defined(__TI_COMPILER_VERSION__) + #define DECLARE_ALIGNED(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + t __attribute__((aligned(n))) v + #define DECLARE_ASM_CONST(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + static const t __attribute__((aligned(n))) v +#elif defined(__GNUC__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v +#elif defined(_MSC_VER) + #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v +#else + #define DECLARE_ALIGNED(n,t,v) t v + #define DECLARE_ASM_CONST(n,t,v) static const t v +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) + #define av_malloc_attrib __attribute__((__malloc__)) +#else + #define av_malloc_attrib +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU). + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a block of size * nmemb bytes with av_malloc(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_malloc() + */ +av_alloc_size(1, 2) void *av_malloc_array(size_t nmemb, size_t size); + +/** + * Allocate or reallocate a block of memory. + * If ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param size Size in bytes of the memory block to be allocated or + * reallocated. + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + * @see av_fast_realloc() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate or reallocate a block of memory. + * This function does the same thing as av_realloc, except: + * - It takes two arguments and checks the result of the multiplication for + * integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic "buf = realloc(buf); if (!buf) return -1;". + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate or reallocate a block of memory. + * If *ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param size Size in bytes for the memory block to be allocated or + * reallocated + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_reallocp(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate or reallocate an array. + * If ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate or reallocate an array through a pointer to a pointer. + * If *ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc(). + * @param ptr Pointer to the memory block which should be freed. + * @note ptr = NULL is explicitly allowed. + * @note It is recommended that you use av_freep() instead. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if it cannot be allocated. + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a block of nmemb * size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * The allocation will fail if nmemb * size is greater than or equal + * to INT_MAX. + * @param nmemb + * @param size + * @return Pointer to the allocated block, NULL if it cannot be allocated. + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib; + +/** + * Allocate a block of size * nmemb bytes with av_mallocz(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + * @see av_malloc_array() + */ +av_alloc_size(1, 2) void *av_mallocz_array(size_t nmemb, size_t size); + +/** + * Duplicate the string s. + * @param s string to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of s or NULL if the string cannot be allocated. + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of the string s. + * @param s string to be duplicated + * @param len the maximum length of the resulting string (not counting the + * terminating byte). + * @return Pointer to a newly-allocated string containing a + * copy of s or NULL if the string cannot be allocated. + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate the buffer p. + * @param p buffer to be duplicated + * @return Pointer to a newly allocated buffer containing a + * copy of p or NULL if the buffer cannot be allocated. + */ +void *av_memdup(const void *p, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc() and set the pointer pointing to it to NULL. + * @param ptr Pointer to the pointer to the memory block which should + * be freed. + * @note passing a pointer to a NULL pointer is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Add an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @return >=0 on success, negative otherwise. + * @see av_dynarray_add(), av_dynarray2_add() + */ +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size elem_size to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem_size size in bytes of the elements in the array + * @param elem_data pointer to the data of the element to add. If NULL, the space of + * the new added element is not filled. + * @return pointer to the data of the element to copy in the new allocated space. + * If NULL, the new allocated space is left uninitialized." + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * Multiply two size_t values checking for overflow. + * @return 0 if success, AVERROR(EINVAL) if overflow. + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: only try the division if nelem and elsize + * are both greater than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +/** + * Set the maximum size that may me allocated in one block. + */ +void av_max_alloc(size_t max); + +/** + * deliberately overlapping memcpy implementation + * @param dst destination buffer + * @param back how many bytes back we start (the initial size of the overlapping window), must be > 0 + * @param cnt number of bytes to copy, must be >= 0 + * + * cnt > back is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of back. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * Reallocate the given block if it is not large enough, otherwise do nothing. + * + * @see av_realloc + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special + * handling to avoid memleaks is necessary. + * + * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer + * @param size size of the buffer *ptr points to + * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and + * *size 0 if an error occurred. + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/libavutil/motion_vector.h b/libavutil/motion_vector.h new file mode 100644 index 0000000..30cfb99 --- /dev/null +++ b/libavutil/motion_vector.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/libavutil/murmur3.h b/libavutil/murmur3.h new file mode 100644 index 0000000..f29ed97 --- /dev/null +++ b/libavutil/murmur3.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +struct AVMurMur3 *av_murmur3_alloc(void); +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); +void av_murmur3_init(struct AVMurMur3 *c); +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/libavutil/old_pix_fmts.h b/libavutil/old_pix_fmts.h new file mode 100644 index 0000000..cd1ed7c --- /dev/null +++ b/libavutil/old_pix_fmts.h @@ -0,0 +1,177 @@ +/* + * copyright (c) 2006-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OLD_PIX_FMTS_H +#define AVUTIL_OLD_PIX_FMTS_H + +/* + * This header exists to prevent new pixel formats from being accidentally added + * to the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVPixelFormat enum instead. + */ + PIX_FMT_NONE = AV_PIX_FMT_NONE, + PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_GRAY8, ///< Y , 8bpp + PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range + PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range + PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + PIX_FMT_XVMC_MPEG2_IDCT, +#endif /* FF_API_XVMC */ + PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range + PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 + PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 + + PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 + PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 + + PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 + PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1 + PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1 + PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha + PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + //the following 10 formats have the disadvantage of needing 1 format for each bit depth, thus + //If you want to support multiple bit depths, then using PIX_FMT_YUV420P16* with the bpp stored separately + //is better + PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + +#ifdef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big endian + PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little endian + PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big endian + PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little endian + PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big endian + PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little endian + +#ifndef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB... + PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0... + PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR... + PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0... + PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + + PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big endian + PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little endian + PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big endian + PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little endian + + PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +#endif /* AVUTIL_OLD_PIX_FMTS_H */ diff --git a/libavutil/opencl.h b/libavutil/opencl.h new file mode 100644 index 0000000..4655cba --- /dev/null +++ b/libavutil/opencl.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2012 Peng Gao + * Copyright (C) 2012 Li Cao + * Copyright (C) 2012 Wei Gao + * Copyright (C) 2013 Lenny Wang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * OpenCL wrapper + * + * This interface is considered still experimental and its API and ABI may + * change without prior notice. + */ + +#ifndef LIBAVUTIL_OPENCL_H +#define LIBAVUTIL_OPENCL_H + +#include "config.h" +#if HAVE_CL_CL_H +#include +#else +#include +#endif +#include +#include "dict.h" + +#include "libavutil/version.h" + +#define AV_OPENCL_KERNEL( ... )# __VA_ARGS__ + +#define AV_OPENCL_MAX_KERNEL_NAME_SIZE 150 + +#define AV_OPENCL_MAX_DEVICE_NAME_SIZE 100 + +#define AV_OPENCL_MAX_PLATFORM_NAME_SIZE 100 + +typedef struct { + int device_type; + char device_name[AV_OPENCL_MAX_DEVICE_NAME_SIZE]; + cl_device_id device_id; +} AVOpenCLDeviceNode; + +typedef struct { + cl_platform_id platform_id; + char platform_name[AV_OPENCL_MAX_PLATFORM_NAME_SIZE]; + int device_num; + AVOpenCLDeviceNode **device_node; +} AVOpenCLPlatformNode; + +typedef struct { + int platform_num; + AVOpenCLPlatformNode **platform_node; +} AVOpenCLDeviceList; + +typedef struct { + cl_platform_id platform_id; + cl_device_type device_type; + cl_context context; + cl_device_id device_id; + cl_command_queue command_queue; + char *platform_name; +} AVOpenCLExternalEnv; + +/** + * Get OpenCL device list. + * + * It must be freed with av_opencl_free_device_list(). + * + * @param device_list pointer to OpenCL environment device list, + * should be released by av_opencl_free_device_list() + * + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_get_device_list(AVOpenCLDeviceList **device_list); + +/** + * Free OpenCL device list. + * + * @param device_list pointer to OpenCL environment device list + * created by av_opencl_get_device_list() + */ +void av_opencl_free_device_list(AVOpenCLDeviceList **device_list); + +/** + * Set option in the global OpenCL context. + * + * This options affect the operation performed by the next + * av_opencl_init() operation. + * + * The currently accepted options are: + * - platform: set index of platform in device list + * - device: set index of device in device list + * + * See reference "OpenCL Specification Version: 1.2 chapter 5.6.4". + * + * @param key option key + * @param val option value + * @return >=0 on success, a negative error code in case of failure + * @see av_opencl_get_option() + */ +int av_opencl_set_option(const char *key, const char *val); + +/** + * Get option value from the global OpenCL context. + * + * @param key option key + * @param out_val pointer to location where option value will be + * written, must be freed with av_freep() + * @return >=0 on success, a negative error code in case of failure + * @see av_opencl_set_option() + */ +int av_opencl_get_option(const char *key, uint8_t **out_val); + +/** + * Free option values of the global OpenCL context. + * + */ +void av_opencl_free_option(void); + +/** + * Allocate OpenCL external environment. + * + * It must be freed with av_opencl_free_external_env(). + * + * @return pointer to allocated OpenCL external environment + */ +AVOpenCLExternalEnv *av_opencl_alloc_external_env(void); + +/** + * Free OpenCL external environment. + * + * @param ext_opencl_env pointer to OpenCL external environment + * created by av_opencl_alloc_external_env() + */ +void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env); + +/** + * Get OpenCL error string. + * + * @param status OpenCL error code + * @return OpenCL error string + */ +const char *av_opencl_errstr(cl_int status); + +/** + * Register kernel code. + * + * The registered kernel code is stored in a global context, and compiled + * in the runtime environment when av_opencl_init() is called. + * + * @param kernel_code kernel code to be compiled in the OpenCL runtime environment + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_register_kernel_code(const char *kernel_code); + +/** + * Initialize the run time OpenCL environment + * + * @param ext_opencl_env external OpenCL environment, created by an + * application program, ignored if set to NULL + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env); + +/** + * compile specific OpenCL kernel source + * + * @param program_name pointer to a program name used for identification + * @param build_opts pointer to a string that describes the preprocessor + * build options to be used for building the program + * @return a cl_program object + */ +cl_program av_opencl_compile(const char *program_name, const char* build_opts); + +/** + * get OpenCL command queue + * + * @return a cl_command_queue object + */ +cl_command_queue av_opencl_get_command_queue(void); + +/** + * Create OpenCL buffer. + * + * The buffer is used to save the data used or created by an OpenCL + * kernel. + * The created buffer must be released with av_opencl_buffer_release(). + * + * See clCreateBuffer() function reference for more information about + * the parameters. + * + * @param cl_buf pointer to OpenCL buffer + * @param cl_buf_size size in bytes of the OpenCL buffer to create + * @param flags flags used to control buffer attributes + * @param host_ptr host pointer of the OpenCL buffer + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr); + +/** + * Write OpenCL buffer with data from src_buf. + * + * @param dst_cl_buf pointer to OpenCL destination buffer + * @param src_buf pointer to source buffer + * @param buf_size size in bytes of the source and destination buffers + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size); + +/** + * Read data from OpenCL buffer to memory buffer. + * + * @param dst_buf pointer to destination buffer (CPU memory) + * @param src_cl_buf pointer to source OpenCL buffer + * @param buf_size size in bytes of the source and destination buffers + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size); + +/** + * Write image data from memory to OpenCL buffer. + * + * The source must be an array of pointers to image plane buffers. + * + * @param dst_cl_buf pointer to destination OpenCL buffer + * @param dst_cl_buf_size size in bytes of OpenCL buffer + * @param dst_cl_buf_offset the offset of the OpenCL buffer start position + * @param src_data array of pointers to source plane buffers + * @param src_plane_sizes array of sizes in bytes of the source plane buffers + * @param src_plane_num number of source image planes + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, + uint8_t **src_data, int *plane_size, int plane_num); + +/** + * Read image data from OpenCL buffer. + * + * @param dst_data array of pointers to destination plane buffers + * @param dst_plane_sizes array of pointers to destination plane buffers + * @param dst_plane_num number of destination image planes + * @param src_cl_buf pointer to source OpenCL buffer + * @param src_cl_buf_size size in bytes of OpenCL buffer + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, + cl_mem src_cl_buf, size_t cl_buffer_size); + +/** + * Release OpenCL buffer. + * + * @param cl_buf pointer to OpenCL buffer to release, which was + * previously filled with av_opencl_buffer_create() + */ +void av_opencl_buffer_release(cl_mem *cl_buf); + +/** + * Release OpenCL environment. + * + * The OpenCL environment is effectively released only if all the created + * kernels had been released with av_opencl_release_kernel(). + */ +void av_opencl_uninit(void); + +/** + * Benchmark an OpenCL device with a user defined callback function. This function + * sets up an external OpenCL environment including context and command queue on + * the device then tears it down in the end. The callback function should perform + * the rest of the work. + * + * @param device pointer to the OpenCL device to be used + * @param platform cl_platform_id handle to which the device belongs to + * @param benchmark callback function to perform the benchmark, return a + * negative value in case of failure + * @return the score passed from the callback function, a negative error code in case + * of failure + */ +int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device, cl_platform_id platform, + int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env)); + +#endif /* LIBAVUTIL_OPENCL_H */ diff --git a/libavutil/opencl_internal.h b/libavutil/opencl_internal.h new file mode 100644 index 0000000..dacd930 --- /dev/null +++ b/libavutil/opencl_internal.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 Peng Gao + * Copyright (C) 2012 Li Cao + * Copyright (C) 2012 Wei Gao + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opencl.h" + +#define FF_OPENCL_PARAM_INFO(a) ((void*)(&(a))), (sizeof(a)) + +typedef struct { + cl_kernel kernel; + int param_num; + void *ctx; +} FFOpenclParam; + +int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...); diff --git a/libavutil/opt.h b/libavutil/opt.h new file mode 100644 index 0000000..7338e78 --- /dev/null +++ b/libavutil/opt.h @@ -0,0 +1,897 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_malloc(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This allows to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_CONST = 128, + AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), + AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), + AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational + AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), + AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), + AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), +#if FF_API_OLD_AVOPTIONS + FF_OPT_TYPE_FLAGS = 0, + FF_OPT_TYPE_INT, + FF_OPT_TYPE_INT64, + FF_OPT_TYPE_DOUBLE, + FF_OPT_TYPE_FLOAT, + FF_OPT_TYPE_STRING, + FF_OPT_TYPE_RATIONAL, + FF_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + FF_OPT_TYPE_CONST=128, +#endif +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#if FF_API_OPT_TYPE_METADATA +#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... +#endif +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is inteded for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + + +#if FF_API_OLD_AVOPTIONS +/** + * Set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an + * AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. If the field is not of a string + * type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param[out] o_out if non-NULL put here a pointer to the AVOption + * found + * @param alloc this parameter is currently ignored + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + * @deprecated use av_opt_set() + */ +attribute_deprecated +int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out); + +attribute_deprecated const AVOption *av_set_double(void *obj, const char *name, double n); +attribute_deprecated const AVOption *av_set_q(void *obj, const char *name, AVRational n); +attribute_deprecated const AVOption *av_set_int(void *obj, const char *name, int64_t n); + +double av_get_double(void *obj, const char *name, const AVOption **o_out); +AVRational av_get_q(void *obj, const char *name, const AVOption **o_out); +int64_t av_get_int(void *obj, const char *name, const AVOption **o_out); +attribute_deprecated const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len); +attribute_deprecated const AVOption *av_next_option(void *obj, const AVOption *last); +#endif + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +#if FF_API_OLD_AVOPTIONS +attribute_deprecated +void av_opt_set_defaults2(void *s, int mask, int flags); +#endif + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_opt_set() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN 0x0001 /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ 0x0002 + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE 0x1000 + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_opt_set(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Copy options from src object into dest object. + * + * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object. + * Original memory allocated for such options is freed unless both src and dest options points to the same memory. + * + * @param dest Object to copy from + * @param src Object to copy into + * @return 0 on success, negative on error + */ +int av_opt_copy(void *dest, void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Check if given option is set to its default value. + * + * Options o must belong to the obj. This function must not be called to check child's options state. + * @see av_opt_is_set_to_default_by_name(). + * + * @param obj AVClass object to check option on + * @param o option to be checked + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default(void *obj, const AVOption *o); + +/** + * Check if given option is set to its default value. + * + * @param obj AVClass object to check option on + * @param name option name + * @param search_flags combination of AV_OPT_SEARCH_* + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); + + +#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. +#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. + +/** + * Serialize object's options. + * + * Create a string containing object's serialized options. + * Such string may be passed back to av_opt_set_from_string() in order to restore option values. + * + * @param[in] obj AVClass object to serialize + * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG) + * @param[in] flags combination of AV_OPT_SERIALIZE_* flags + * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + */ +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep); +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/libavutil/parseutils.h b/libavutil/parseutils.h new file mode 100644 index 0000000..c80f0de --- /dev/null +++ b/libavutil/parseutils.h @@ -0,0 +1,187 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * In particular it actually supports the parameters: + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this + * function call, or NULL in case the function fails to match all of + * the fmt string and therefore an error occurred + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/libavutil/pca.h b/libavutil/pca.h new file mode 100644 index 0000000..992bb2e --- /dev/null +++ b/libavutil/pca.h @@ -0,0 +1,35 @@ +/* + * principal component analysis (PCA) + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * principal component analysis (PCA) + */ + +#ifndef AVUTIL_PCA_H +#define AVUTIL_PCA_H + +struct PCA *ff_pca_init(int n); +void ff_pca_free(struct PCA *pca); +void ff_pca_add(struct PCA *pca, const double *v); +int ff_pca(struct PCA *pca, double *eigenvector, double *eigenvalue); + +#endif /* AVUTIL_PCA_H */ diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c new file mode 100644 index 0000000..8cfffab --- /dev/null +++ b/libavutil/pixdesc.c @@ -0,0 +1,170 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "avassert.h" +#include "avstring.h" +#include "common.h" +#include "pixfmt.h" +#include "pixdesc.h" +#include "internal.h" +#include "intreadwrite.h" +#include "version.h" + +typedef struct { + enum AVPixelFormat pix_fmt; + AVPixFmtDescriptor desc; +} AVPixFmtDescriptorEntry; + + +static const AVPixFmtDescriptorEntry pix_desc[] = { +#ifdef USE_VAR_BIT_DEPTH + { + AV_PIX_FMT_YUV420P16LE, + { + //.name = "yuv420p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 1, 0, 15 }, /* Y */ + { 1, 1, 1, 0, 15 }, /* U */ + { 2, 1, 1, 0, 15 }, /* V */ + }, + } + }, + { + AV_PIX_FMT_YUV422P16LE, + { + //.name = "yuv422p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 15 }, /* Y */ + { 1, 1, 1, 0, 15 }, /* U */ + { 2, 1, 1, 0, 15 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + } + }, + { + AV_PIX_FMT_YUV444P16LE, + { + //.name = "yuv444p16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 15 }, /* Y */ + { 1, 1, 1, 0, 15 }, /* U */ + { 2, 1, 1, 0, 15 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + } + }, + { + AV_PIX_FMT_GRAY16LE, + { + //.name = "gray16le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 15 }, /* Y */ + }, + //.alias = "y16le", + }, + }, +#else + { + AV_PIX_FMT_YUV420P, + { + //.name = "yuv420p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 1, 0, 7 }, /* Y */ + { 1, 1, 1, 0, 7 }, /* U */ + { 2, 1, 1, 0, 7 }, /* V */ + }, + } + }, + { + AV_PIX_FMT_YUV422P16LE, + { + //.name = "yuv422p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 7 }, /* Y */ + { 1, 1, 1, 0, 7 }, /* U */ + { 2, 1, 1, 0, 7 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + } + }, + { + AV_PIX_FMT_YUV444P, + { + //.name = "yuv444p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 7 }, /* Y */ + { 1, 1, 1, 0, 7 }, /* U */ + { 2, 1, 1, 0, 7 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + } + }, + { + AV_PIX_FMT_GRAY8, + { + //.name = "gray", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 1, 0, 7 }, /* Y */ + }, + }, + }, +#endif +}; + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt) +{ + int i; + for(i = 0; i < countof(pix_desc); i++) { + if (pix_desc[i].pix_fmt == pix_fmt) { + return &pix_desc[i].desc; + } + } + return NULL; +} diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h new file mode 100644 index 0000000..a4376b2 --- /dev/null +++ b/libavutil/pixdesc.h @@ -0,0 +1,385 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + uint16_t plane : 2; + + /** + * Number of elements between 2 horizontally consecutive pixels minus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t step_minus1 : 3; + + /** + * Number of elements before the component of the first pixel plus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t offset_plus1 : 3; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + uint16_t shift : 3; + + /** + * Number of bits in the component minus 1. + */ + uint16_t depth_minus1 : 4; +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = -((-luma_width) >> log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= -((-luma_height) >> log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + uint8_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 2 or 4 components, then alpha is last. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components, + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) +/** + * The pixel format is "pseudo-paletted". This means that FFmpeg treats it as + * paletted internally, but the palette is generated by the decoder and is not + * stored in the file. + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) +/** + * The pixel format has an alpha channel. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +#if FF_API_PIX_FMT +/** + * @deprecated use the AV_PIX_FMT_FLAG_* flags + */ +#define PIX_FMT_BE AV_PIX_FMT_FLAG_BE +#define PIX_FMT_PAL AV_PIX_FMT_FLAG_PAL +#define PIX_FMT_BITSTREAM AV_PIX_FMT_FLAG_BITSTREAM +#define PIX_FMT_HWACCEL AV_PIX_FMT_FLAG_HWACCEL +#define PIX_FMT_PLANAR AV_PIX_FMT_FLAG_PLANAR +#define PIX_FMT_RGB AV_PIX_FMT_FLAG_RGB +#define PIX_FMT_PSEUDOPAL AV_PIX_FMT_FLAG_PSEUDOPAL +#define PIX_FMT_ALPHA AV_PIX_FMT_FLAG_ALPHA +#endif + +#if FF_API_PIX_FMT_DESC +/** + * The array of all the pixel format descriptors. + */ +extern attribute_deprecated const AVPixFmtDescriptor av_pix_fmt_descriptors[]; +#endif + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +void ff_check_pixfmt_descriptors(void); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/libavutil/pixelutils.h b/libavutil/pixelutils.h new file mode 100644 index 0000000..a8dbc15 --- /dev/null +++ b/libavutil/pixelutils.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * @file + * pixel format definitions + * + */ + +#include "libavutil/avconfig.h" +#include "version.h" + +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @par + * When the pixel format is palettized RGB (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8bit per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + * + * @note + * Make sure that all newly added big-endian formats have (pix_fmt & 1) == 1 + * and that all newly added little-endian formats have (pix_fmt & 1) == 0. + * This allows simpler detection of big vs little-endian. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + AV_PIX_FMT_XVMC_MPEG2_IDCT, +#define AV_PIX_FMT_XVMC AV_PIX_FMT_XVMC_MPEG2_IDCT +#endif /* FF_API_XVMC */ + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 + + AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + AV_PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1 + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1 + AV_PIX_FMT_YA8, ///< 8bit gray, 8bit alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + +#ifdef AV_PIX_FMT_ABI_GIT_MASTER + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + + /** + * duplicated pixel formats for compatibility with libav. + * FFmpeg supports these formats since May 8 2012 and Jan 28 2012 (commits f9ca1ac7 and 143a5c55) + * Libav added them Oct 12 2012 with incompatible values (commit 6d5600e85) + */ + AV_PIX_FMT_YUVA422P_LIBAV, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P_LIBAV, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + /** + * duplicated pixel formats for compatibility with libav. + * FFmpeg supports these formats since Sat Sep 24 06:01:45 2011 +0200 (commits 9569a3c9f41387a8c7d1ce97d8693520477a66c3) + * also see Fri Nov 25 01:38:21 2011 +0100 92afb431621c79155fcb7171d26f137eb1bee028 + * Libav added them Sun Mar 16 23:05:47 2014 +0100 with incompatible values (commit 1481d24c3a0abf81e1d7a514547bd5305232be30) + */ + AV_PIX_FMT_RGBA64BE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_VDA, ///< HW acceleration through VDA, data[3] contains a CVPixelBufferRef + + AV_PIX_FMT_YA16BE, ///< 16bit gray, 16bit alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16bit gray, 16bit alpha (little-endian) + + +#ifndef AV_PIX_FMT_ABI_GIT_MASTER + AV_PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + AV_PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB... + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0... + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR... + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0... + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ +#if !FF_API_XVMC + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing +#endif /* !FF_API_XVMC */ + + AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions + +#if FF_API_PIX_FMT +#include "old_pix_fmts.h" +#endif +}; + +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI +#define AV_PIX_FMT_YUVA422P AV_PIX_FMT_YUVA422P_LIBAV +#define AV_PIX_FMT_YUVA444P AV_PIX_FMT_YUVA444P_LIBAV +#define AV_PIX_FMT_RGBA64BE AV_PIX_FMT_RGBA64BE_LIBAV +#define AV_PIX_FMT_RGBA64LE AV_PIX_FMT_RGBA64LE_LIBAV +#define AV_PIX_FMT_BGRA64BE AV_PIX_FMT_BGRA64BE_LIBAV +#define AV_PIX_FMT_BGRA64LE AV_PIX_FMT_BGRA64LE_LIBAV +#endif + + +#define AV_PIX_FMT_Y400A AV_PIX_FMT_GRAY8A +#define AV_PIX_FMT_GBR24P AV_PIX_FMT_GBRP + +#if AV_HAVE_BIGENDIAN +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_RGB32 AV_PIX_FMT_NE(ARGB, BGRA) +#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR) +#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA) +#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB) +#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) +#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) + +#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) +#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) +#define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) +#define AV_PIX_FMT_RGB565 AV_PIX_FMT_NE(RGB565BE, RGB565LE) +#define AV_PIX_FMT_RGB555 AV_PIX_FMT_NE(RGB555BE, RGB555LE) +#define AV_PIX_FMT_RGB444 AV_PIX_FMT_NE(RGB444BE, RGB444LE) +#define AV_PIX_FMT_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE) +#define AV_PIX_FMT_BGR48 AV_PIX_FMT_NE(BGR48BE, BGR48LE) +#define AV_PIX_FMT_BGR565 AV_PIX_FMT_NE(BGR565BE, BGR565LE) +#define AV_PIX_FMT_BGR555 AV_PIX_FMT_NE(BGR555BE, BGR555LE) +#define AV_PIX_FMT_BGR444 AV_PIX_FMT_NE(BGR444BE, BGR444LE) +#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) +#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE) +#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE) +#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE) +#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE) +#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE) +#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE) + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) + +#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE) +#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE) +#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) +#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) + + +#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) +#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) +#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) +#define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) +#define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) +#define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) +#define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) +#define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) + +#define AV_PIX_FMT_XYZ12 AV_PIX_FMT_NE(XYZ12BE, XYZ12LE) +#define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) + + +#if FF_API_PIX_FMT +#define PixelFormat AVPixelFormat + +#define PIX_FMT_Y400A AV_PIX_FMT_Y400A +#define PIX_FMT_GBR24P AV_PIX_FMT_GBR24P + +#define PIX_FMT_NE(be, le) AV_PIX_FMT_NE(be, le) + +#define PIX_FMT_RGB32 AV_PIX_FMT_RGB32 +#define PIX_FMT_RGB32_1 AV_PIX_FMT_RGB32_1 +#define PIX_FMT_BGR32 AV_PIX_FMT_BGR32 +#define PIX_FMT_BGR32_1 AV_PIX_FMT_BGR32_1 +#define PIX_FMT_0RGB32 AV_PIX_FMT_0RGB32 +#define PIX_FMT_0BGR32 AV_PIX_FMT_0BGR32 + +#define PIX_FMT_GRAY16 AV_PIX_FMT_GRAY16 +#define PIX_FMT_RGB48 AV_PIX_FMT_RGB48 +#define PIX_FMT_RGB565 AV_PIX_FMT_RGB565 +#define PIX_FMT_RGB555 AV_PIX_FMT_RGB555 +#define PIX_FMT_RGB444 AV_PIX_FMT_RGB444 +#define PIX_FMT_BGR48 AV_PIX_FMT_BGR48 +#define PIX_FMT_BGR565 AV_PIX_FMT_BGR565 +#define PIX_FMT_BGR555 AV_PIX_FMT_BGR555 +#define PIX_FMT_BGR444 AV_PIX_FMT_BGR444 + +#define PIX_FMT_YUV420P9 AV_PIX_FMT_YUV420P9 +#define PIX_FMT_YUV422P9 AV_PIX_FMT_YUV422P9 +#define PIX_FMT_YUV444P9 AV_PIX_FMT_YUV444P9 +#define PIX_FMT_YUV420P10 AV_PIX_FMT_YUV420P10 +#define PIX_FMT_YUV422P10 AV_PIX_FMT_YUV422P10 +#define PIX_FMT_YUV444P10 AV_PIX_FMT_YUV444P10 +#define PIX_FMT_YUV420P12 AV_PIX_FMT_YUV420P12 +#define PIX_FMT_YUV422P12 AV_PIX_FMT_YUV422P12 +#define PIX_FMT_YUV444P12 AV_PIX_FMT_YUV444P12 +#define PIX_FMT_YUV420P14 AV_PIX_FMT_YUV420P14 +#define PIX_FMT_YUV422P14 AV_PIX_FMT_YUV422P14 +#define PIX_FMT_YUV444P14 AV_PIX_FMT_YUV444P14 +#define PIX_FMT_YUV420P16 AV_PIX_FMT_YUV420P16 +#define PIX_FMT_YUV422P16 AV_PIX_FMT_YUV422P16 +#define PIX_FMT_YUV444P16 AV_PIX_FMT_YUV444P16 + +#define PIX_FMT_RGBA64 AV_PIX_FMT_RGBA64 +#define PIX_FMT_BGRA64 AV_PIX_FMT_BGRA64 +#define PIX_FMT_GBRP9 AV_PIX_FMT_GBRP9 +#define PIX_FMT_GBRP10 AV_PIX_FMT_GBRP10 +#define PIX_FMT_GBRP12 AV_PIX_FMT_GBRP12 +#define PIX_FMT_GBRP14 AV_PIX_FMT_GBRP14 +#define PIX_FMT_GBRP16 AV_PIX_FMT_GBRP16 +#endif + +/** + * Chromaticity coordinates of the source primaries. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_NB, ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10 bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12 bit system + AVCOL_TRC_NB, ///< Not part of ABI +}; + +/** + * YUV colorspace type. + */ +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above + AVCOL_SPC_SMPTE240M = 7, + AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_NB, ///< Not part of ABI +}; +#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG + + +/** + * MPEG vs JPEG YUV range. + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB, ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * X X 3 4 X X are luma samples, + * 1 2 1-6 are possible chroma positions + * X X 5 6 X 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< mpeg2/4, h264 default + AVCHROMA_LOC_CENTER = 2, ///< mpeg1, jpeg, h263 + AVCHROMA_LOC_TOPLEFT = 3, ///< DV + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB, ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ diff --git a/libavutil/qsort.h b/libavutil/qsort.h new file mode 100644 index 0000000..30edcc8 --- /dev/null +++ b/libavutil/qsort.h @@ -0,0 +1,117 @@ +/* + * copyright (c) 2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" + + +/** + * Quicksort + * This sort is fast, and fully inplace but not stable and it is possible + * to construct input that requires O(n^2) time but this is very unlikely to + * happen with non constructed input. + */ +#define AV_QSORT(p, num, type, cmp) {\ + void *stack[64][2];\ + int sp= 1;\ + stack[0][0] = p;\ + stack[0][1] = (p)+(num)-1;\ + while(sp){\ + type *start= stack[--sp][0];\ + type *end = stack[ sp][1];\ + while(start < end){\ + if(start < end-1) {\ + int checksort=0;\ + type *right = end-2;\ + type *left = start+1;\ + type *mid = start + ((end-start)>>1);\ + if(cmp(start, end) > 0) {\ + if(cmp( end, mid) > 0) FFSWAP(type, *start, *mid);\ + else FFSWAP(type, *start, *end);\ + }else{\ + if(cmp(start, mid) > 0) FFSWAP(type, *start, *mid);\ + else checksort= 1;\ + }\ + if(cmp(mid, end) > 0){ \ + FFSWAP(type, *mid, *end);\ + checksort=0;\ + }\ + if(start == end-2) break;\ + FFSWAP(type, end[-1], *mid);\ + while(left <= right){\ + while(left<=right && cmp(left, end-1) < 0)\ + left++;\ + while(left<=right && cmp(right, end-1) > 0)\ + right--;\ + if(left <= right){\ + FFSWAP(type, *left, *right);\ + left++;\ + right--;\ + }\ + }\ + FFSWAP(type, end[-1], *left);\ + if(checksort && (mid == left-1 || mid == left)){\ + mid= start;\ + while(mid 0)\ + FFSWAP(type, *start, *end);\ + break;\ + }\ + }\ + }\ +} + +/** + * Merge sort, this sort requires a temporary buffer and is stable, its worst + * case time is O(n log n) + * @param p must be a lvalue pointer, this function may exchange it with tmp + * @param tmp must be a lvalue pointer, this function may exchange it with p + */ +#define AV_MSORT(p, tmp, num, type, cmp) {\ + unsigned i, j, step;\ + for(step=1; step<(num); step+=step){\ + for(i=0; i<(num); i+=2*step){\ + unsigned a[2] = {i, i+step};\ + unsigned end = FFMIN(i+2*step, (num));\ + for(j=i; a[0] 0;\ + tmp[j] = p[ a[idx]++ ];\ + }\ + if(a[0]>=i+step) a[0] = a[1];\ + for(; j + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/libavutil/rational.h b/libavutil/rational.h new file mode 100644 index 0000000..7439701 --- /dev/null +++ b/libavutil/rational.h @@ -0,0 +1,166 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * rational numbers + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_math + * @{ + */ + +/** + * rational number numerator/denominator + */ +typedef struct AVRational{ + int num; ///< numerator + int den; ///< denominator +} AVRational; + +/** + * Create a rational. + * Useful for compilers that do not support compound literals. + * @note The return value is not reduced. + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. + * @param a first rational + * @param b second rational + * @return 0 if a==b, 1 if a>b, -1 if a>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; +} + +/** + * Convert rational to double. + * @param a rational to convert + * @return (double) a + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * This is useful for framerate calculations. + * @param dst_num destination numerator + * @param dst_den destination denominator + * @param num source numerator + * @param den source denominator + * @param max the maximum allowed for dst_num & dst_den + * @return 1 if exact, 0 otherwise + */ +int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); + +/** + * Multiply two rationals. + * @param b first rational + * @param c second rational + * @return b*c + */ +AVRational av_mul_q(AVRational b, AVRational c) av_const; + +/** + * Divide one rational by another. + * @param b first rational + * @param c second rational + * @return b/c + */ +AVRational av_div_q(AVRational b, AVRational c) av_const; + +/** + * Add two rationals. + * @param b first rational + * @param c second rational + * @return b+c + */ +AVRational av_add_q(AVRational b, AVRational c) av_const; + +/** + * Subtract one rational from another. + * @param b first rational + * @param c second rational + * @return b-c + */ +AVRational av_sub_q(AVRational b, AVRational c) av_const; + +/** + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * inf is expressed as {1,0} or {-1,0} depending on the sign. + * + * @param d double to convert + * @param max the maximum allowed numerator and denominator + * @return (AVRational) d + */ +AVRational av_d2q(double d, int max) av_const; + +/** + * @return 1 if q1 is nearer to q than q2, -1 if q2 is nearer + * than q1, 0 if they have the same distance. + */ +int av_nearer_q(AVRational q, AVRational q1, AVRational q2); + +/** + * Find the nearest value in q_list to q. + * @param q_list an array of rationals terminated by {0, 0} + * @return the index of the nearest value found in the array + */ +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); + +/** + * @} + */ + +#endif /* AVUTIL_RATIONAL_H */ diff --git a/libavutil/rc4.h b/libavutil/rc4.h new file mode 100644 index 0000000..9362fd8 --- /dev/null +++ b/libavutil/rc4.h @@ -0,0 +1,50 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RC4_H +#define AVUTIL_RC4_H + +#include + +struct AVRC4 { + uint8_t state[256]; + int x, y; +}; + +/** + * @brief Initializes an AVRC4 context. + * + * @param key_bits must be a multiple of 8 + * @param decrypt 0 for encryption, 1 for decryption, currently has no effect + */ +int av_rc4_init(struct AVRC4 *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the RC4 algorithm. + * + * @param count number of bytes + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst, may be NULL + * @param iv not (yet) used for RC4, should be NULL + * @param decrypt 0 for encryption, 1 for decryption, not (yet) used + */ +void av_rc4_crypt(struct AVRC4 *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +#endif /* AVUTIL_RC4_H */ diff --git a/libavutil/replaygain.h b/libavutil/replaygain.h new file mode 100644 index 0000000..5c03e19 --- /dev/null +++ b/libavutil/replaygain.h @@ -0,0 +1,51 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/libavutil/ripemd.h b/libavutil/ripemd.h new file mode 100644 index 0000000..7b0c8bc --- /dev/null +++ b/libavutil/ripemd.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/libavutil/samplefmt.h b/libavutil/samplefmt.h new file mode 100644 index 0000000..6a8a031 --- /dev/null +++ b/libavutil/samplefmt.h @@ -0,0 +1,271 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + * + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/libavutil/sha.h b/libavutil/sha.h new file mode 100644 index 0000000..bf4377e --- /dev/null +++ b/libavutil/sha.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/libavutil/sha512.h b/libavutil/sha512.h new file mode 100644 index 0000000..7b08701 --- /dev/null +++ b/libavutil/sha512.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA512 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/libavutil/softfloat.h b/libavutil/softfloat.h new file mode 100644 index 0000000..8647e6a --- /dev/null +++ b/libavutil/softfloat.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SOFTFLOAT_H +#define AVUTIL_SOFTFLOAT_H + +#include +#include "common.h" + +#include "avassert.h" + +#define MIN_EXP -126 +#define MAX_EXP 126 +#define ONE_BITS 29 + +typedef struct SoftFloat{ + int32_t exp; + int32_t mant; +}SoftFloat; + +static av_const SoftFloat av_normalize_sf(SoftFloat a){ + if(a.mant){ +#if 1 + while((a.mant + 0x20000000U)<0x40000000U){ + a.mant += a.mant; + a.exp -= 1; + } +#else + int s=ONE_BITS + 1 - av_log2(a.mant ^ (a.mant<<1)); + a.exp -= s; + a.mant <<= s; +#endif + if(a.exp < MIN_EXP){ + a.exp = MIN_EXP; + a.mant= 0; + } + }else{ + a.exp= MIN_EXP; + } + return a; +} + +static inline av_const SoftFloat av_normalize1_sf(SoftFloat a){ +#if 1 + if((int32_t)(a.mant + 0x40000000U) < 0){ + a.exp++; + a.mant>>=1; + } + av_assert2(a.mant < 0x40000000 && a.mant > -0x40000000); + return a; +#elif 1 + int t= a.mant + 0x40000000 < 0; + return (SoftFloat){a.exp+t, a.mant>>t}; +#else + int t= (a.mant + 0x40000000U)>>31; + return (SoftFloat){a.exp+t, a.mant>>t}; +#endif +} + +/** + * @return Will not be more denormalized than a+b. So if either input is + * normalized, then the output will not be worse then the other input. + * If both are normalized, then the output will be normalized. + */ +static inline av_const SoftFloat av_mul_sf(SoftFloat a, SoftFloat b){ + a.exp += b.exp; + av_assert2((int32_t)((a.mant * (int64_t)b.mant) >> ONE_BITS) == (a.mant * (int64_t)b.mant) >> ONE_BITS); + a.mant = (a.mant * (int64_t)b.mant) >> ONE_BITS; + return av_normalize1_sf(a); +} + +/** + * b has to be normalized and not zero. + * @return Will not be more denormalized than a. + */ +static av_const SoftFloat av_div_sf(SoftFloat a, SoftFloat b){ + a.exp -= b.exp+1; + a.mant = ((int64_t)a.mant<<(ONE_BITS+1)) / b.mant; + return av_normalize1_sf(a); +} + +static inline av_const int av_cmp_sf(SoftFloat a, SoftFloat b){ + int t= a.exp - b.exp; + if(t<0) return (a.mant >> (-t)) - b.mant ; + else return a.mant - (b.mant >> t); +} + +static inline av_const SoftFloat av_add_sf(SoftFloat a, SoftFloat b){ + int t= a.exp - b.exp; + if (t <-31) return b; + else if (t < 0) return av_normalize1_sf((SoftFloat){b.exp, b.mant + (a.mant >> (-t))}); + else if (t < 32) return av_normalize1_sf((SoftFloat){a.exp, a.mant + (b.mant >> t )}); + else return a; +} + +static inline av_const SoftFloat av_sub_sf(SoftFloat a, SoftFloat b){ + return av_add_sf(a, (SoftFloat){b.exp, -b.mant}); +} + +//FIXME sqrt, log, exp, pow, sin, cos + +static inline av_const SoftFloat av_int2sf(int v, int frac_bits){ + return av_normalize_sf((SoftFloat){ONE_BITS-frac_bits, v}); +} + +/** + * Rounding is to -inf. + */ +static inline av_const int av_sf2int(SoftFloat v, int frac_bits){ + v.exp += frac_bits - ONE_BITS; + if(v.exp >= 0) return v.mant << v.exp ; + else return v.mant >>(-v.exp); +} + +#endif /* AVUTIL_SOFTFLOAT_H */ diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h new file mode 100644 index 0000000..1135dc9 --- /dev/null +++ b/libavutil/stereo3d.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + */ + AV_STEREO3D_COLUMNS, +}; + + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/libavutil/threadmessage.h b/libavutil/threadmessage.h new file mode 100644 index 0000000..a8481d8 --- /dev/null +++ b/libavutil/threadmessage.h @@ -0,0 +1,91 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/libavutil/time.h b/libavutil/time.h new file mode 100644 index 0000000..dc169b0 --- /dev/null +++ b/libavutil/time.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * The returned values may not be monotonic on platforms where a monotonic + * clock is not available. + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/libavutil/time_internal.h b/libavutil/time_internal.h new file mode 100644 index 0000000..612a75a --- /dev/null +++ b/libavutil/time_internal.h @@ -0,0 +1,47 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_INTERNAL_H +#define AVUTIL_TIME_INTERNAL_H + +#include +#include "config.h" + +#if !HAVE_GMTIME_R && !defined(gmtime_r) +static inline struct tm *gmtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = gmtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#endif + +#if !HAVE_LOCALTIME_R && !defined(localtime_r) +static inline struct tm *localtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = localtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#endif + +#endif /* AVUTIL_TIME_INTERNAL_H */ diff --git a/libavutil/timecode.h b/libavutil/timecode.h new file mode 100644 index 0000000..56e3975 --- /dev/null +++ b/libavutil/timecode.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 16 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/libavutil/timer.h b/libavutil/timer.h new file mode 100644 index 0000000..13a3c8c --- /dev/null +++ b/libavutil/timer.h @@ -0,0 +1,90 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * high precision timer, useful to profile code + */ + +#ifndef AVUTIL_TIMER_H +#define AVUTIL_TIMER_H + +#include +#include +#include + +#include "config.h" + +#if HAVE_MACH_MACH_TIME_H +#include +#endif + +#include "log.h" + +#if ARCH_ARM +# include "arm/timer.h" +#elif ARCH_PPC +# include "ppc/timer.h" +#elif ARCH_X86 +# include "x86/timer.h" +#endif + +#if !defined(AV_READ_TIME) +# if HAVE_GETHRTIME +# define AV_READ_TIME gethrtime +# elif HAVE_MACH_ABSOLUTE_TIME +# define AV_READ_TIME mach_absolute_time +# endif +#endif + +#ifndef FF_TIMER_UNITS +# define FF_TIMER_UNITS "UNITS" +#endif + +#ifdef AV_READ_TIME +#define START_TIMER \ + uint64_t tend; \ + uint64_t tstart = AV_READ_TIME(); \ + +#define STOP_TIMER(id) \ + tend = AV_READ_TIME(); \ + { \ + static uint64_t tsum = 0; \ + static int tcount = 0; \ + static int tskip_count = 0; \ + if (tcount < 2 || \ + tend - tstart < 8 * tsum / tcount || \ + tend - tstart < 2000) { \ + tsum+= tend - tstart; \ + tcount++; \ + } else \ + tskip_count++; \ + if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \ + av_log(NULL, AV_LOG_ERROR, \ + "%"PRIu64" " FF_TIMER_UNITS " in %s, %d runs, %d skips\n", \ + tsum * 10 / tcount, id, tcount, tskip_count); \ + } \ + } +#else +#define START_TIMER +#define STOP_TIMER(id) { } +#endif + +#endif /* AVUTIL_TIMER_H */ diff --git a/libavutil/timestamp.h b/libavutil/timestamp.h new file mode 100644 index 0000000..f010a7e --- /dev/null +++ b/libavutil/timestamp.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/libavutil/tree.h b/libavutil/tree.h new file mode 100644 index 0000000..a14fa91 --- /dev/null +++ b/libavutil/tree.h @@ -0,0 +1,132 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_TREE_H +#define AVUTIL_TREE_H + +#include "attributes.h" +#include "version.h" + +/** + * @addtogroup lavu_tree AVTree + * @ingroup lavu_data + * + * Low-complexity tree container + * + * Insertion, removal, finding equal, largest which is smaller than and + * smallest which is larger than, all have O(log n) worst-case complexity. + * @{ + */ + + +struct AVTreeNode; +extern const int av_tree_node_size; + +/** + * Allocate an AVTreeNode. + */ +struct AVTreeNode *av_tree_node_alloc(void); + +/** + * Find an element. + * @param root a pointer to the root node of the tree + * @param next If next is not NULL, then next[0] will contain the previous + * element and next[1] the next element. If either does not exist, + * then the corresponding entry in next is unchanged. + * @return An element with cmp(key, elem) == 0 or NULL if no such element + * exists in the tree. + */ +void *av_tree_find(const struct AVTreeNode *root, void *key, + int (*cmp)(void *key, const void *b), void *next[2]); + +/** + * Insert or remove an element. + * + * If *next is NULL, then the supplied element will be removed if it exists. + * If *next is non-NULL, then the supplied element will be inserted, unless + * it already exists in the tree. + * + * @param rootp A pointer to a pointer to the root node of the tree; note that + * the root node can change during insertions, this is required + * to keep the tree balanced. + * @param key pointer to the element key to insert in the tree + * @param next Used to allocate and free AVTreeNodes. For insertion the user + * must set it to an allocated and zeroed object of at least + * av_tree_node_size bytes size. av_tree_insert() will set it to + * NULL if it has been consumed. + * For deleting elements *next is set to NULL by the user and + * av_tree_insert() will set it to the AVTreeNode which was + * used for the removed element. + * This allows the use of flat arrays, which have + * lower overhead compared to many malloced elements. + * You might want to define a function like: + * @code + * void *tree_insert(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b), + * AVTreeNode **next) + * { + * if (!*next) + * *next = av_mallocz(av_tree_node_size); + * return av_tree_insert(rootp, key, cmp, next); + * } + * void *tree_remove(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b, AVTreeNode **next)) + * { + * av_freep(next); + * return av_tree_insert(rootp, key, cmp, next); + * } + * @endcode + * @param cmp compare function used to compare elements in the tree + * @return If no insertion happened, the found element; if an insertion or + * removal happened, then either key or NULL will be returned. + * Which one it is depends on the tree state and the implementation. You + * should make no assumptions that it's one or the other in the code. + */ +void *av_tree_insert(struct AVTreeNode **rootp, void *key, + int (*cmp)(void *key, const void *b), + struct AVTreeNode **next); + +void av_tree_destroy(struct AVTreeNode *t); + +/** + * Apply enu(opaque, &elem) to all the elements in the tree in a given range. + * + * @param cmp a comparison function that returns < 0 for a element below the + * range, > 0 for a element above the range and == 0 for a + * element inside the range + * + * @note The cmp function should use the same ordering used to construct the + * tree. + */ +void av_tree_enumerate(struct AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)); + +/** + * @} + */ + +#endif /* AVUTIL_TREE_H */ diff --git a/libavutil/version.h b/libavutil/version.h new file mode 100644 index 0000000..bf7c7ef --- /dev/null +++ b/libavutil/version.h @@ -0,0 +1,137 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * @} + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 54 +#define LIBAVUTIL_VERSION_MINOR 13 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @} + * + * @defgroup depr_guards Deprecation guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @{ + */ + +#ifndef FF_API_OLD_AVOPTIONS +#define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT +#define FF_API_PIX_FMT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CONTEXT_SIZE +#define FF_API_CONTEXT_SIZE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT_DESC +#define FF_API_PIX_FMT_DESC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AV_REVERSE +#define FF_API_AV_REVERSE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AUDIOCONVERT +#define FF_API_AUDIOCONVERT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CPU_FLAG_MMX2 +#define FF_API_CPU_FLAG_MMX2 (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_LLS_PRIVATE +#define FF_API_LLS_PRIVATE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AVFRAME_LAVC +#define FF_API_AVFRAME_LAVC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_VDPAU +#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT +#define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_OPT_TYPE_METADATA +#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 55) +#endif + + +#ifndef FF_CONST_AVUTIL53 +#if LIBAVUTIL_VERSION_MAJOR >= 53 +#define FF_CONST_AVUTIL53 const +#else +#define FF_CONST_AVUTIL53 +#endif +#endif + +/** + * @} + */ + +#endif /* AVUTIL_VERSION_H */ + diff --git a/libavutil/x86_cpu.h b/libavutil/x86_cpu.h new file mode 100644 index 0000000..bec1c77 --- /dev/null +++ b/libavutil/x86_cpu.h @@ -0,0 +1 @@ +#include "libavutil/x86/asm.h" diff --git a/libavutil/xga_font_data.h b/libavutil/xga_font_data.h new file mode 100644 index 0000000..5e40f54 --- /dev/null +++ b/libavutil/xga_font_data.h @@ -0,0 +1,35 @@ +/* + * CGA/EGA/VGA ROM font data + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * CGA/EGA/VGA ROM font data + */ + +#ifndef AVUTIL_XGA_FONT_DATA_H +#define AVUTIL_XGA_FONT_DATA_H + +#include +#include "internal.h" + +extern av_export const uint8_t avpriv_cga_font[2048]; +extern av_export const uint8_t avpriv_vga16_font[4096]; + +#endif /* AVUTIL_XGA_FONT_DATA_H */ diff --git a/libavutil/xtea.h b/libavutil/xtea.h new file mode 100644 index 0000000..6f1e71e --- /dev/null +++ b/libavutil/xtea.h @@ -0,0 +1,64 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/libbpg.c b/libbpg.c new file mode 100644 index 0000000..8c5162e --- /dev/null +++ b/libbpg.c @@ -0,0 +1,1560 @@ +/* + * libbpg + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#ifdef EMSCRIPTEN +#include +#endif + +#include +#include +#include + +#ifndef EMSCRIPTEN +#define USE_RGB48 +//#define DEBUG +#endif + +#if !defined(DEBUG) +#define NDEBUG +#endif + +#include +#include "libbpg.h" + +#define BPG_HEADER_MAGIC 0x425047fb + +#define ITAPS2 4 +#define ITAPS (2 * ITAPS2) /* number of taps of the interpolation filter */ + +#ifdef USE_VAR_BIT_DEPTH +typedef uint16_t PIXEL; +#else +typedef uint8_t PIXEL; +#endif + +#define MAX_DATA_SIZE ((1 << 30) - 1) + +typedef struct { + int c_shift; + int c_rnd; + int c_one; + int y_one, y_offset; + int c_r_cr, c_g_cb, c_g_cr, c_b_cb; + int c_center; + int bit_depth; + int limited_range; +} ColorConvertState; + +typedef void ColorConvertFunc(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr); + +struct BPGDecoderContext { + AVFrame *frame; + AVFrame *alpha_frame; + int w, h; + BPGImageFormatEnum format; + uint8_t has_alpha; /* true if alpha or W plane */ + uint8_t bit_depth; + uint8_t has_w_plane; + uint8_t limited_range; + uint8_t premultiplied_alpha; + BPGColorSpaceEnum color_space; + int keep_extension_data; /* true if the extension data must be + kept during parsing */ + BPGExtensionData *first_md; + + /* the following is used for format conversion */ + uint8_t is_rgba; + uint8_t is_rgb48; + int y; /* current line */ + int w2, h2; + const uint8_t *y_buf, *cb_buf, *cr_buf, *a_buf; + int y_linesize, cb_linesize, cr_linesize, a_linesize; + PIXEL *cb_buf2, *cr_buf2, *cb_buf3[ITAPS], *cr_buf3[ITAPS]; + int16_t *c_buf4; + ColorConvertState cvt; + ColorConvertFunc *cvt_func; +}; + +/* ffmpeg utilities */ +#ifdef USE_AV_LOG +void av_log(void* avcl, int level, const char *fmt, ...) +{ +#ifdef DEBUG + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +#endif +} + +void avpriv_report_missing_feature(void *avc, const char *msg, ...) +{ +#ifdef DEBUG + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); +#endif +} +#endif /* USE_AV_LOG */ + +/* return < 0 if error, otherwise the consumed length */ +static int get_ue32(uint32_t *pv, const uint8_t *buf, int len) +{ + const uint8_t *p; + uint32_t v; + int a; + + if (len <= 0) + return -1; + p = buf; + a = *p++; + len--; + if (a < 0x80) { + *pv = a; + return 1; + } else if (a == 0x80) { + /* we don't accept non canonical encodings */ + return -1; + } + v = a & 0x7f; + for(;;) { + if (len <= 0) + return -1; + a = *p++; + len--; + v = (v << 7) | (a & 0x7f); + if (!(a & 0x80)) + break; + } + *pv = v; + return p - buf; +} + +static int get_ue(uint32_t *pv, const uint8_t *buf, int len) +{ + int ret; + ret = get_ue32(pv, buf, len); + if (ret < 0) + return ret; + /* limit the maximum size to avoid overflows in buffer + computations */ + if (*pv > MAX_DATA_SIZE) + return -1; + return ret; +} + +static int decode_write_frame(AVCodecContext *avctx, + AVFrame *frame, int *frame_count, AVPacket *pkt, int last) +{ + int len, got_frame; + + len = avcodec_decode_video2(avctx, frame, &got_frame, pkt); + if (len < 0) { +#ifdef DEBUG + fprintf(stderr, "Error while decoding frame %d\n", *frame_count); +#endif + return len; + } + if (got_frame) { +#ifdef DEBUG + printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count); +#endif + (*frame_count)++; + } + if (pkt->data) { + pkt->size -= len; + pkt->data += len; + } + return 0; +} + +extern AVCodec ff_hevc_decoder; + +static AVFrame *hevc_decode(const uint8_t *input_data, int input_data_len, + int width, int height, int chroma_format_idc, + int bit_depth) +{ + AVCodec *codec; + AVCodecContext *c= NULL; + int frame_count, idx, msps_len, ret, buf_len, i; + AVPacket avpkt; + AVFrame *frame; + uint32_t len; + uint8_t *buf, *msps_buf; + + /* build the modified SPS header to please libavcodec */ + ret = get_ue(&len, input_data, input_data_len); + if (ret < 0) + return NULL; + input_data += ret; + input_data_len -= ret; + + if (len > input_data_len) + return NULL; + + msps_len = 1 + 4 + 4 + 1 + len; + msps_buf = av_malloc(msps_len); + idx = 0; + msps_buf[idx++] = chroma_format_idc; + msps_buf[idx++] = (width >> 24); + msps_buf[idx++] = (width >> 16); + msps_buf[idx++] = (width >> 8); + msps_buf[idx++] = (width >> 0); + msps_buf[idx++] = (height >> 24); + msps_buf[idx++] = (height >> 16); + msps_buf[idx++] = (height >> 8); + msps_buf[idx++] = (height >> 0); + msps_buf[idx++] = bit_depth - 8; + memcpy(msps_buf + idx, input_data, len); + idx += len; + assert(idx == msps_len); + input_data += len; + input_data_len -= len; + + buf_len = 4 + 2 + msps_len * 2 + 4 + (input_data_len - len); + buf = av_malloc(buf_len); + + idx = 0; + /* NAL header */ + buf[idx++] = 0x00; + buf[idx++] = 0x00; + buf[idx++] = 0x00; + buf[idx++] = 0x01; + buf[idx++] = (48 << 1); /* application specific NAL unit type */ + buf[idx++] = 1; + + /* add the modified SPS with the correct escape codes */ + i = 0; + while (i < msps_len) { + if ((i + 1) < msps_len && msps_buf[i] == 0 && msps_buf[i + 1] == 0) { + buf[idx++] = 0x00; + buf[idx++] = 0x00; + buf[idx++] = 0x03; + i += 2; + } else { + buf[idx++] = msps_buf[i++]; + } + } + /* the last byte cannot be 0 */ + if (idx == 0 || buf[idx - 1] == 0x00) + buf[idx++] = 0x80; + + av_free(msps_buf); + + /* NAL start code (Note: should be 3 bytes depending on exact NAL + type, but it is not critical for libavcodec) */ + buf[idx++] = 0x00; + buf[idx++] = 0x00; + buf[idx++] = 0x00; + buf[idx++] = 0x01; + + memcpy(buf + idx, input_data, input_data_len); + idx += input_data_len; + + assert(idx < buf_len); + + av_init_packet(&avpkt); + + codec = &ff_hevc_decoder; + + c = avcodec_alloc_context3(codec); + if (!c) { +#ifdef DEBUG + fprintf(stderr, "Could not allocate video codec context\n"); +#endif + exit(1); + } + + if(codec->capabilities&CODEC_CAP_TRUNCATED) + c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */ + + /* for testing: use the MD5 or CRC in SEI to check the decoded bit + stream. */ + c->err_recognition |= AV_EF_CRCCHECK; + + /* open it */ + if (avcodec_open2(c, codec, NULL) < 0) { +#ifdef DEBUG + fprintf(stderr, "Could not open codec\n"); +#endif + exit(1); + } + + frame = av_frame_alloc(); + if (!frame) { +#ifdef DEBUG + fprintf(stderr, "Could not allocate video frame\n"); +#endif + return NULL; + } + + avpkt.size = idx; + avpkt.data = buf; + frame_count = 0; + while (avpkt.size > 0) { + if (decode_write_frame(c, frame, &frame_count, &avpkt, 0) < 0) + exit(1); + } + + avcodec_close(c); + av_free(c); + av_free(buf); + + if (frame_count == 0) { + av_frame_free(&frame); + return NULL; + } else { + return frame; + } +} + +uint8_t *bpg_decoder_get_data(BPGDecoderContext *img, int *pline_size, int plane) +{ + int c_count; + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + if (plane < c_count) { + *pline_size = img->frame->linesize[plane]; + return img->frame->data[plane]; + } else if (img->has_alpha && plane == c_count) { + *pline_size = img->alpha_frame->linesize[0]; + return img->alpha_frame->data[0]; + } else { + *pline_size = 0; + return NULL; + } +} + +int bpg_decoder_get_info(BPGDecoderContext *img, BPGImageInfo *p) +{ + if (!img->frame) + return -1; + p->width = img->w; + p->height = img->h; + p->format = img->format; + p->has_alpha = img->has_alpha && !img->has_w_plane; + p->premultiplied_alpha = img->premultiplied_alpha; + p->has_w_plane = img->has_w_plane; + p->limited_range = img->limited_range; + p->color_space = img->color_space; + p->bit_depth = img->bit_depth; + return 0; +} + +static inline int clamp_pix(int a, int pixel_max) +{ + if (a < 0) + return 0; + else if (a > pixel_max) + return pixel_max; + else + return a; +} + +static inline int clamp8(int a) +{ + if (a < 0) + return 0; + else if (a > 255) + return 255; + else + return a; +} + +/* 7 tap Lanczos interpolator */ +#define IC0 (-1) +#define IC1 4 +#define IC2 (-10) +#define IC3 57 +#define IC4 18 +#define IC5 (-6) +#define IC6 2 + +/* interpolate by a factor of two assuming chroma is between the luma + samples. */ +static void interp2_simple(PIXEL *dst, const PIXEL *src, int n, int bit_depth) +{ + int pixel_max, a0, a1, a2, a3, a4, a5, a6; + + pixel_max = (1 << bit_depth) - 1; + + a1 = src[-3]; + a2 = src[-2]; + a3 = src[-1]; + a4 = src[0]; + a5 = src[1]; + a6 = src[2]; + + while (n >= 2) { + a0 = a1; + a1 = a2; + a2 = a3; + a3 = a4; + a4 = a5; + a5 = a6; + a6 = src[3]; + dst[0] = clamp_pix((a0 * IC6 + a1 * IC5 + a2 * IC4 + a3 * IC3 + + a4 * IC2 + a5 * IC1 + a6 * IC0 + 32) >> 6, + pixel_max); + dst[1] = clamp_pix((a0 * IC0 + a1 * IC1 + a2 * IC2 + a3 * IC3 + + a4 * IC4 + a5 * IC5 + a6 * IC6 + 32) >> 6, + pixel_max); + dst += 2; + src++; + n -= 2; + } + if (n) { + a0 = a1; + a1 = a2; + a2 = a3; + a3 = a4; + a4 = a5; + a5 = a6; + a6 = src[3]; + dst[0] = clamp_pix((a0 * IC6 + a1 * IC5 + a2 * IC4 + a3 * IC3 + + a4 * IC2 + a5 * IC1 + a6 * IC0 + 32) >> 6, + pixel_max); + } +} + +static void interp2_h(PIXEL *dst, const PIXEL *src, int n, int bit_depth) +{ + PIXEL *src1, v; + int i, n2; + + /* add extra pixels and do the interpolation (XXX: could go faster) */ + n2 = (n + 1) / 2; + src1 = av_malloc((n2 + ITAPS - 1) * sizeof(PIXEL)); + memcpy(src1 + ITAPS2 - 1, src, n2 * sizeof(PIXEL)); + + v = src[0]; + for(i = 0; i < ITAPS2 - 1; i++) + src1[i] = v; + + v = src[n2 - 1]; + for(i = 0; i < ITAPS2; i++) + src1[ITAPS2 - 1 + n2 + i] = v; + interp2_simple(dst, src1 + ITAPS2 - 1, n, bit_depth); + av_free(src1); +} + +static void interp2_simple2(PIXEL *dst, const int16_t *src, int n, + int bit_depth) +{ + int shift, offset, pixel_max, a0, a1, a2, a3, a4, a5, a6; + + pixel_max = (1 << bit_depth) - 1; + shift = 20 - bit_depth; + offset = 1 << (shift - 1); + + a1 = src[-3]; + a2 = src[-2]; + a3 = src[-1]; + a4 = src[0]; + a5 = src[1]; + a6 = src[2]; + + while (n >= 2) { + a0 = a1; + a1 = a2; + a2 = a3; + a3 = a4; + a4 = a5; + a5 = a6; + a6 = src[3]; + dst[0] = clamp_pix((a0 * IC6 + a1 * IC5 + a2 * IC4 + a3 * IC3 + + a4 * IC2 + a5 * IC1 + a6 * IC0 + offset) >> shift, + pixel_max); + dst[1] = clamp_pix((a0 * IC0 + a1 * IC1 + a2 * IC2 + a3 * IC3 + + a4 * IC4 + a5 * IC5 + a6 * IC6 + offset) >> shift, + pixel_max); + dst += 2; + src++; + n -= 2; + } + if (n) { + a0 = a1; + a1 = a2; + a2 = a3; + a3 = a4; + a4 = a5; + a5 = a6; + a6 = src[3]; + dst[0] = clamp_pix((a0 * IC6 + a1 * IC5 + a2 * IC4 + a3 * IC3 + + a4 * IC2 + a5 * IC1 + a6 * IC0 + offset) >> shift, + pixel_max); + } +} + +/* y_pos is the position of the sample '0' in the 'src' circular + buffer. tmp is a temporary buffer of length (n2 + 2 * ITAPS - 1) */ +static void interp2_vh(PIXEL *dst, PIXEL **src, int n, int y_pos, + int16_t *tmp_buf, int bit_depth, int frac_pos) +{ + const PIXEL *src0, *src1, *src2, *src3, *src4, *src5, *src6; + int i, n2, shift; + PIXEL v; + + src0 = src[(y_pos - 3) & 7]; + src1 = src[(y_pos - 2) & 7]; + src2 = src[(y_pos - 1) & 7]; + src3 = src[(y_pos + 0) & 7]; + src4 = src[(y_pos + 1) & 7]; + src5 = src[(y_pos + 2) & 7]; + src6 = src[(y_pos + 3) & 7]; + + /* vertical interpolation first */ + /* XXX: should round but not critical */ + shift = bit_depth - 8; + n2 = (n + 1) / 2; + if (frac_pos == 0) { + for(i = 0; i < n2; i++) { + tmp_buf[ITAPS2 - 1 + i] = + (src0[i] * IC6 + src1[i] * IC5 + + src2[i] * IC4 + src3[i] * IC3 + + src4[i] * IC2 + src5[i] * IC1 + + src6[i] * IC0) >> shift; + } + } else { + for(i = 0; i < n2; i++) { + tmp_buf[ITAPS2 - 1 + i] = + (src0[i] * IC0 + src1[i] * IC1 + + src2[i] * IC2 + src3[i] * IC3 + + src4[i] * IC4 + src5[i] * IC5 + + src6[i] * IC6) >> shift; + } + } + + /* then horizontal interpolation */ + v = tmp_buf[ITAPS2 - 1]; + for(i = 0; i < ITAPS2 - 1; i++) + tmp_buf[i] = v; + v = tmp_buf[ITAPS2 - 1 + n2 - 1]; + for(i = 0; i < ITAPS2; i++) + tmp_buf[ITAPS2 - 1 + n2 + i] = v; + interp2_simple2(dst, tmp_buf + ITAPS2 - 1, n, bit_depth); +} + +static void ycc_to_rgb24(ColorConvertState *s, uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint8_t *q = dst; + int y_val, cb_val, cr_val, x; + int c_r_cr, c_g_cb, c_g_cr, c_b_cb, rnd, shift, center, c_one; + + c_r_cr = s->c_r_cr; + c_g_cb = s->c_g_cb; + c_g_cr = s->c_g_cr; + c_b_cb = s->c_b_cb; + c_one = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + center = s->c_center; + for(x = 0; x < n; x++) { + y_val = y_ptr[x] * c_one; + cb_val = cb_ptr[x] - center; + cr_val = cr_ptr[x] - center; + q[0] = clamp8((y_val + c_r_cr * cr_val + rnd) >> shift); + q[1] = clamp8((y_val - c_g_cb * cb_val - c_g_cr * cr_val + rnd) >> shift); + q[2] = clamp8((y_val + c_b_cb * cb_val + rnd) >> shift); + q += incr; + } +} + +static void ycgco_to_rgb24(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint8_t *q = dst; + int y_val, cb_val, cr_val, x; + int rnd, shift, center, c_one; + + c_one = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + center = s->c_center; + for(x = 0; x < n; x++) { + y_val = y_ptr[x]; + cb_val = cb_ptr[x] - center; + cr_val = cr_ptr[x] - center; + q[0] = clamp8(((y_val - cb_val + cr_val) * c_one + rnd) >> shift); + q[1] = clamp8(((y_val + cb_val) * c_one + rnd) >> shift); + q[2] = clamp8(((y_val - cb_val - cr_val) * c_one + rnd) >> shift); + q += incr; + } +} + +/* c = c * alpha */ +static void alpha_combine8(ColorConvertState *s, + uint8_t *dst, const PIXEL *a_ptr, int n, int incr) +{ + uint8_t *q = dst; + int x, a_val, shift, rnd; + + shift = s->bit_depth; + rnd = 1 << (shift - 1); + for(x = 0; x < n; x++) { + a_val = a_ptr[x]; + /* XXX: not accurate enough */ + q[0] = (q[0] * a_val + rnd) >> shift; + q[1] = (q[1] * a_val + rnd) >> shift; + q[2] = (q[2] * a_val + rnd) >> shift; + q += incr; + } +} + +static uint32_t divide8_table[256]; + +#define DIV8_BITS 16 + +static void alpha_divide8_init(void) +{ + int i; + for(i = 1; i < 256; i++) { + /* Note: the 128 is added to have 100% correct results for all + the values */ + divide8_table[i] = ((255 << DIV8_BITS) + (i / 2) + 128) / i; + } +} + +static inline unsigned int comp_divide8(unsigned int val, unsigned int alpha, + unsigned int alpha_inv) +{ + if (val >= alpha) + return 255; + return (val * alpha_inv + (1 << (DIV8_BITS - 1))) >> DIV8_BITS; +} + +/* c = c / alpha */ +static void alpha_divide8(uint8_t *dst, int n) +{ + static int inited; + uint8_t *q = dst; + int x; + unsigned int a_val, a_inv; + + if (!inited) { + inited = 1; + alpha_divide8_init(); + } + + for(x = 0; x < n; x++) { + a_val = q[3]; + if (a_val == 0) { + q[0] = 255; + q[1] = 255; + q[2] = 255; + } else { + a_inv = divide8_table[a_val]; + q[0] = comp_divide8(q[0], a_val, a_inv); + q[1] = comp_divide8(q[1], a_val, a_inv); + q[2] = comp_divide8(q[2], a_val, a_inv); + } + q += 4; + } +} + +static void gray_to_rgb24(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint8_t *q = dst; + int x, y_val, c, rnd, shift; + + if (s->bit_depth == 8 && !s->limited_range) { + for(x = 0; x < n; x++) { + y_val = y_ptr[x]; + q[0] = y_val; + q[1] = y_val; + q[2] = y_val; + q += incr; + } + } else { + c = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + for(x = 0; x < n; x++) { + y_val = clamp8((y_ptr[x] * c + rnd) >> shift); + q[0] = y_val; + q[1] = y_val; + q[2] = y_val; + q += incr; + } + } +} + +static void rgb_to_rgb24(ColorConvertState *s, uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint8_t *q = dst; + int x, c, rnd, shift; + + if (s->bit_depth == 8 && !s->limited_range) { + for(x = 0; x < n; x++) { + q[0] = cr_ptr[x]; + q[1] = y_ptr[x]; + q[2] = cb_ptr[x]; + q += incr; + } + } else { + c = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + for(x = 0; x < n; x++) { + q[0] = clamp8((cr_ptr[x] * c + rnd) >> shift); + q[1] = clamp8((y_ptr[x] * c + rnd) >> shift); + q[2] = clamp8((cb_ptr[x] * c + rnd) >> shift); + q += incr; + } + } +} + +static void put_dummy_gray8(uint8_t *dst, int n, int incr) +{ + int x; + for(x = 0; x < n; x++) { + dst[0] = 0xff; + dst += incr; + } +} + +static void gray_to_gray8(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + int n, int incr) +{ + uint8_t *q = dst; + int x, y_val, c, rnd, shift; + + if (s->bit_depth == 8) { + for(x = 0; x < n; x++) { + y_val = y_ptr[x]; + q[0] = y_val; + q += incr; + } + } else { + c = s->c_one; + rnd = s->c_rnd; + shift = s->c_shift; + for(x = 0; x < n; x++) { + y_val = (y_ptr[x] * c + rnd) >> shift; + q[0] = y_val; + q += incr; + } + } +} + +static ColorConvertFunc *cs_to_rgb24[BPG_CS_COUNT] = { + ycc_to_rgb24, + rgb_to_rgb24, + ycgco_to_rgb24, + ycc_to_rgb24, + ycc_to_rgb24, +}; + +#ifdef USE_RGB48 + +/* 16 bit output */ + +static inline int clamp16(int a) +{ + if (a < 0) + return 0; + else if (a > 65535) + return 65535; + else + return a; +} + +static void ycc_to_rgb48(ColorConvertState *s, uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint16_t *q = (uint16_t *)dst; + int y_val, cb_val, cr_val, x; + int c_r_cr, c_g_cb, c_g_cr, c_b_cb, rnd, shift, center, c_one; + + c_r_cr = s->c_r_cr; + c_g_cb = s->c_g_cb; + c_g_cr = s->c_g_cr; + c_b_cb = s->c_b_cb; + c_one = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + center = s->c_center; + for(x = 0; x < n; x++) { + y_val = y_ptr[x] * c_one; + cb_val = cb_ptr[x] - center; + cr_val = cr_ptr[x] - center; + q[0] = clamp16((y_val + c_r_cr * cr_val + rnd) >> shift); + q[1] = clamp16((y_val - c_g_cb * cb_val - c_g_cr * cr_val + rnd) >> shift); + q[2] = clamp16((y_val + c_b_cb * cb_val + rnd) >> shift); + q += incr; + } +} + +static void ycgco_to_rgb48(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint16_t *q = (uint16_t *)dst; + int y_val, cb_val, cr_val, x; + int rnd, shift, center, c_one; + + c_one = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + center = s->c_center; + for(x = 0; x < n; x++) { + y_val = y_ptr[x]; + cb_val = cb_ptr[x] - center; + cr_val = cr_ptr[x] - center; + q[0] = clamp16(((y_val - cb_val + cr_val) * c_one + rnd) >> shift); + q[1] = clamp16(((y_val + cb_val) * c_one + rnd) >> shift); + q[2] = clamp16(((y_val - cb_val - cr_val) * c_one + rnd) >> shift); + q += incr; + } +} + +static void gray_to_rgb48(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + uint16_t *q = (uint16_t *)dst; + int x, y_val, c, rnd, shift; + + c = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + for(x = 0; x < n; x++) { + y_val = clamp16((y_ptr[x] * c + rnd) >> shift); + q[0] = y_val; + q[1] = y_val; + q[2] = y_val; + q += incr; + } +} + +static void gray_to_gray16(ColorConvertState *s, + uint16_t *dst, const PIXEL *y_ptr, + int n, int incr) +{ + uint16_t *q = dst; + int x, y_val, c, rnd, shift; + + c = s->c_one; + rnd = s->c_rnd; + shift = s->c_shift; + for(x = 0; x < n; x++) { + y_val = (y_ptr[x] * c + rnd) >> shift; + q[0] = y_val; + q += incr; + } +} + +static void luma_to_gray16(ColorConvertState *s, + uint16_t *dst, const PIXEL *y_ptr, + int n, int incr) +{ + uint16_t *q = dst; + int x, y_val, c, rnd, shift; + + c = s->y_one; + rnd = s->y_offset; + shift = s->c_shift; + for(x = 0; x < n; x++) { + y_val = clamp16((y_ptr[x] * c + rnd) >> shift); + q[0] = y_val; + q += incr; + } +} + +static void rgb_to_rgb48(ColorConvertState *s, + uint8_t *dst, const PIXEL *y_ptr, + const PIXEL *cb_ptr, const PIXEL *cr_ptr, + int n, int incr) +{ + luma_to_gray16(s, (uint16_t *)dst + 1, y_ptr, n, incr); + luma_to_gray16(s, (uint16_t *)dst + 2, cb_ptr, n, incr); + luma_to_gray16(s, (uint16_t *)dst + 0, cr_ptr, n, incr); +} + +static void put_dummy_gray16(uint16_t *dst, int n, int incr) +{ + int x; + for(x = 0; x < n; x++) { + dst[0] = 0xffff; + dst += incr; + } +} + +/* c = c * alpha */ +static void alpha_combine16(ColorConvertState *s, + uint16_t *dst, const PIXEL *a_ptr, int n, int incr) +{ + uint16_t *q = dst; + int x, a_val, shift, rnd; + + shift = s->bit_depth; + rnd = 1 << (shift - 1); + for(x = 0; x < n; x++) { + a_val = a_ptr[x]; + /* XXX: not accurate enough */ + q[0] = (q[0] * a_val + rnd) >> shift; + q[1] = (q[1] * a_val + rnd) >> shift; + q[2] = (q[2] * a_val + rnd) >> shift; + q += incr; + } +} + +#define DIV16_BITS 15 + +static unsigned int comp_divide16(unsigned int val, unsigned int alpha, + unsigned int alpha_inv) +{ + if (val >= alpha) + return 65535; + return (val * alpha_inv + (1 << (DIV16_BITS - 1))) >> DIV16_BITS; +} + +/* c = c / alpha */ +static void alpha_divide16(uint16_t *dst, int n) +{ + uint16_t *q = dst; + int x; + unsigned int a_val, a_inv; + + for(x = 0; x < n; x++) { + a_val = q[3]; + if (a_val == 0) { + q[0] = 65535; + q[1] = 65535; + q[2] = 65535; + } else { + a_inv = ((65535 << DIV16_BITS) + (a_val / 2)) / a_val; + q[0] = comp_divide16(q[0], a_val, a_inv); + q[1] = comp_divide16(q[1], a_val, a_inv); + q[2] = comp_divide16(q[2], a_val, a_inv); + } + q += 4; + } +} + +static ColorConvertFunc *cs_to_rgb48[BPG_CS_COUNT] = { + ycc_to_rgb48, + rgb_to_rgb48, + ycgco_to_rgb48, + ycc_to_rgb48, + ycc_to_rgb48, +}; +#endif + +static void convert_init(ColorConvertState *s, + int in_bit_depth, int out_bit_depth, + BPGColorSpaceEnum color_space, + int limited_range) +{ + int c_shift, in_pixel_max, out_pixel_max; + double mult, k_r, k_b, mult_y, mult_c; + + c_shift = 30 - out_bit_depth; + in_pixel_max = (1 << in_bit_depth) - 1; + out_pixel_max = (1 << out_bit_depth) - 1; + mult = (double)out_pixel_max * (1 << c_shift) / (double)in_pixel_max; + if (limited_range) { + mult_y = (double)out_pixel_max * (1 << c_shift) / + (double)(219 << (in_bit_depth - 8)); + mult_c = (double)out_pixel_max * (1 << c_shift) / + (double)(224 << (in_bit_depth - 8)); + } else { + mult_y = mult; + mult_c = mult; + } + switch(color_space) { + case BPG_CS_YCbCr: + k_r = 0.299; + k_b = 0.114; + goto convert_ycc; + case BPG_CS_YCbCr_BT709: + k_r = 0.2126; + k_b = 0.0722; + goto convert_ycc; + case BPG_CS_YCbCr_BT2020: + k_r = 0.2627; + k_b = 0.0593; + convert_ycc: + s->c_r_cr = lrint(2*(1-k_r) * mult_c); + s->c_g_cb = lrint(2*k_b*(1-k_b)/(1-k_b-k_r) * mult_c); + s->c_g_cr = lrint(2*k_r*(1-k_r)/(1-k_b-k_r) * mult_c); + s->c_b_cb = lrint(2*(1-k_b) * mult_c); + break; + default: + break; + } + s->c_one = lrint(mult); + s->c_shift = c_shift; + s->c_rnd = (1 << (c_shift - 1)); + s->c_center = 1 << (in_bit_depth - 1); + if (limited_range) { + s->y_one = lrint(mult_y); + s->y_offset = -(16 << (in_bit_depth - 8)) * s->y_one + s->c_rnd; + } else { + s->y_one = s->c_one; + s->y_offset = s->c_rnd; + } + s->bit_depth = in_bit_depth; + s->limited_range = limited_range; +} + +static int bpg_decoder_output_init(BPGDecoderContext *s, + BPGDecoderOutputFormat out_fmt) +{ + int i, y1, c_idx; + PIXEL *cb_ptr, *cr_ptr; + +#ifdef USE_RGB48 + if ((unsigned)out_fmt > BPG_OUTPUT_FORMAT_RGBA64) + return -1; +#else + if ((unsigned)out_fmt > BPG_OUTPUT_FORMAT_RGBA32) + return -1; +#endif + s->is_rgba = (out_fmt == BPG_OUTPUT_FORMAT_RGBA32 || + out_fmt == BPG_OUTPUT_FORMAT_RGBA64); + s->is_rgb48 = (out_fmt == BPG_OUTPUT_FORMAT_RGB48 || + out_fmt == BPG_OUTPUT_FORMAT_RGBA64); + + s->y_buf = bpg_decoder_get_data(s, &s->y_linesize, 0); + if (s->format != BPG_FORMAT_GRAY) { + s->cb_buf = bpg_decoder_get_data(s, &s->cb_linesize, 1); + s->cr_buf = bpg_decoder_get_data(s, &s->cr_linesize, 2); + c_idx = 3; + } else { + c_idx = 1; + } + if (s->has_alpha) + s->a_buf = bpg_decoder_get_data(s, &s->a_linesize, c_idx); + else + s->a_buf = NULL; + + if (s->format == BPG_FORMAT_420 || s->format == BPG_FORMAT_422) { + s->w2 = (s->w + 1) / 2; + s->h2 = (s->h + 1) / 2; + s->cb_buf2 = av_malloc(s->w * sizeof(PIXEL)); + s->cr_buf2 = av_malloc(s->w * sizeof(PIXEL)); + + if (s->format == BPG_FORMAT_420) { + for(i = 0; i < ITAPS; i++) { + s->cb_buf3[i] = av_malloc(s->w2 * sizeof(PIXEL)); + s->cr_buf3[i] = av_malloc(s->w2 * sizeof(PIXEL)); + } + s->c_buf4 = av_malloc((s->w2 + 2 * ITAPS2 - 1) * sizeof(int16_t)); + + /* init the vertical interpolation buffer */ + for(i = 0; i < ITAPS; i++) { + y1 = i; + if (y1 > ITAPS2) + y1 -= ITAPS; + if (y1 < 0) + y1 = 0; + else if (y1 >= s->h2) + y1 = s->h2 - 1; + cb_ptr = (PIXEL *)(s->cb_buf + y1 * s->cb_linesize); + cr_ptr = (PIXEL *)(s->cr_buf + y1 * s->cr_linesize); + memcpy(s->cb_buf3[i], cb_ptr, s->w2 * sizeof(PIXEL)); + memcpy(s->cr_buf3[i], cr_ptr, s->w2 * sizeof(PIXEL)); + } + } + } + convert_init(&s->cvt, s->bit_depth, s->is_rgb48 ? 16 : 8, + s->color_space, s->limited_range); + + if (s->format == BPG_FORMAT_GRAY) { +#ifdef USE_RGB48 + if (s->is_rgb48) { + s->cvt_func = gray_to_rgb48; + } else +#endif + { + s->cvt_func = gray_to_rgb24; + } + } else { +#ifdef USE_RGB48 + if (s->is_rgb48) { + s->cvt_func = cs_to_rgb48[s->color_space]; + } else +#endif + { + s->cvt_func = cs_to_rgb24[s->color_space]; + } + } + return 0; +} + +static void bpg_decoder_output_end(BPGDecoderContext *s) +{ + int i; + + av_free(s->cb_buf2); + av_free(s->cr_buf2); + for(i = 0; i < ITAPS; i++) { + av_free(s->cb_buf3[i]); + av_free(s->cr_buf3[i]); + } + av_free(s->c_buf4); +} + +int bpg_decoder_get_line(BPGDecoderContext *s, void *rgb_line1) +{ + uint8_t *rgb_line = rgb_line1; + int w, h, y, pos, y2, y1, incr; + PIXEL *y_ptr, *cb_ptr, *cr_ptr, *a_ptr; + + w = s->w; + h = s->h; + y = s->y; + + if ((unsigned)y >= h) + return -1; + + y_ptr = (PIXEL *)(s->y_buf + y * s->y_linesize); + incr = 3 + s->is_rgba; + switch(s->format) { + case BPG_FORMAT_GRAY: + s->cvt_func(&s->cvt, rgb_line, y_ptr, NULL, NULL, w, incr); + break; + case BPG_FORMAT_420: + y2 = y >> 1; + pos = y2 % ITAPS; + if ((y & 1) == 0) { + interp2_vh(s->cb_buf2, s->cb_buf3, w, pos, s->c_buf4, + s->bit_depth, 0); + interp2_vh(s->cr_buf2, s->cr_buf3, w, pos, s->c_buf4, + s->bit_depth, 0); + } else { + interp2_vh(s->cb_buf2, s->cb_buf3, w, pos, s->c_buf4, + s->bit_depth, 1); + interp2_vh(s->cr_buf2, s->cr_buf3, w, pos, s->c_buf4, + s->bit_depth, 1); + + /* add a new line in the circular buffer */ + pos = (pos + ITAPS2 + 1) % ITAPS; + y1 = y2 + ITAPS2 + 1; + if (y1 >= s->h2) + y1 = s->h2 - 1; + cb_ptr = (PIXEL *)(s->cb_buf + y1 * s->cb_linesize); + cr_ptr = (PIXEL *)(s->cr_buf + y1 * s->cr_linesize); + memcpy(s->cb_buf3[pos], cb_ptr, s->w2 * sizeof(PIXEL)); + memcpy(s->cr_buf3[pos], cr_ptr, s->w2 * sizeof(PIXEL)); + } + s->cvt_func(&s->cvt, rgb_line, y_ptr, s->cb_buf2, s->cr_buf2, w, incr); + break; + case BPG_FORMAT_422: + cb_ptr = (PIXEL *)(s->cb_buf + y * s->cb_linesize); + cr_ptr = (PIXEL *)(s->cr_buf + y * s->cr_linesize); + interp2_h(s->cb_buf2, cb_ptr, w, s->bit_depth); + interp2_h(s->cr_buf2, cr_ptr, w, s->bit_depth); + s->cvt_func(&s->cvt, rgb_line, y_ptr, s->cb_buf2, s->cr_buf2, w, incr); + break; + case BPG_FORMAT_444: + cb_ptr = (PIXEL *)(s->cb_buf + y * s->cb_linesize); + cr_ptr = (PIXEL *)(s->cr_buf + y * s->cr_linesize); + s->cvt_func(&s->cvt, rgb_line, y_ptr, cb_ptr, cr_ptr, w, incr); + break; + default: + return -1; + } + + /* alpha output or CMYK handling */ + if (s->has_w_plane) { + a_ptr = (PIXEL *)(s->a_buf + y * s->a_linesize); +#ifdef USE_RGB48 + if (s->is_rgb48) { + alpha_combine16(&s->cvt, (uint16_t *)rgb_line, a_ptr, w, incr); + if (s->is_rgba) + put_dummy_gray16((uint16_t *)rgb_line + 3, w, 4); + } else +#endif + { + alpha_combine8(&s->cvt, rgb_line, a_ptr, w, incr); + if (s->is_rgba) + put_dummy_gray8(rgb_line + 3, w, 4); + } + } else { + if (s->is_rgba) { +#ifdef USE_RGB48 + if (s->is_rgb48) { + if (s->has_alpha) { + a_ptr = (PIXEL *)(s->a_buf + y * s->a_linesize); + gray_to_gray16(&s->cvt, + (uint16_t *)rgb_line + 3, a_ptr, w, 4); + if (s->premultiplied_alpha) + alpha_divide16((uint16_t *)rgb_line, w); + } else { + put_dummy_gray16((uint16_t *)rgb_line + 3, w, 4); + } + } else +#endif + { + if (s->has_alpha) { + a_ptr = (PIXEL *)(s->a_buf + y * s->a_linesize); + gray_to_gray8(&s->cvt, rgb_line + 3, a_ptr, w, 4); + if (s->premultiplied_alpha) + alpha_divide8((uint8_t *)rgb_line, w); + } else { + put_dummy_gray8(rgb_line + 3, w, 4); + } + } + } + } + + /* go to next line */ + s->y++; + return 0; +} + +int bpg_decoder_start(BPGDecoderContext *s, BPGDecoderOutputFormat out_fmt) +{ + int ret; + + if (!s->frame || s->y >= 0) + return -1; + ret = bpg_decoder_output_init(s, out_fmt); + if (ret) + return ret; + s->y = 0; + return 0; +} + +BPGDecoderContext *bpg_decoder_open(void) +{ + BPGDecoderContext *s; + + s = av_mallocz(sizeof(BPGDecoderContext)); + if (!s) + return NULL; + return s; +} + +typedef struct { + uint32_t width, height; + BPGImageFormatEnum format; + uint8_t has_alpha; + uint8_t bit_depth; + uint8_t has_w_plane; + uint8_t premultiplied_alpha; + uint8_t limited_range; + BPGColorSpaceEnum color_space; + uint32_t ycc_data_len; + uint32_t alpha_data_len; + BPGExtensionData *first_md; +} BPGHeaderData; + +static int bpg_decode_header(BPGHeaderData *h, + const uint8_t *buf, int buf_len, + int header_only, int load_extensions) +{ + int idx, flags1, flags2, has_extension, ret, alpha1_flag, alpha2_flag; + uint32_t extension_data_len; + + if (buf_len < 6) + return -1; + /* check magic */ + if (buf[0] != ((BPG_HEADER_MAGIC >> 24) & 0xff) || + buf[1] != ((BPG_HEADER_MAGIC >> 16) & 0xff) || + buf[2] != ((BPG_HEADER_MAGIC >> 8) & 0xff) || + buf[3] != ((BPG_HEADER_MAGIC >> 0) & 0xff)) + return -1; + idx = 4; + flags1 = buf[idx++]; + h->format = flags1 >> 5; + if (h->format > 3) + return -1; + alpha1_flag = (flags1 >> 4) & 1; + h->bit_depth = (flags1 & 0xf) + 8; + if (h->bit_depth > 14) + return -1; + flags2 = buf[idx++]; + h->color_space = (flags2 >> 4) & 0xf; + has_extension = (flags2 >> 3) & 1; + alpha2_flag = (flags2 >> 2) & 1; + h->limited_range = (flags2 >> 1) & 1; + + h->has_alpha = 0; + h->has_w_plane = 0; + h->premultiplied_alpha = 0; + + if (alpha1_flag) { + h->has_alpha = 1; + h->premultiplied_alpha = alpha2_flag; + } else if (alpha2_flag) { + h->has_alpha = 1; + h->has_w_plane = 1; + } + + if (h->color_space >= BPG_CS_COUNT || + (h->format == BPG_FORMAT_GRAY && h->color_space != 0) || + (h->has_w_plane && h->format == BPG_FORMAT_GRAY)) + return -1; + ret = get_ue(&h->width, buf + idx, buf_len - idx); + if (ret < 0) + return -1; + idx += ret; + ret = get_ue(&h->height, buf + idx, buf_len - idx); + if (ret < 0) + return -1; + idx += ret; + if (h->width == 0 || h->height == 0) + return -1; + if (header_only) + return idx; + + ret = get_ue(&h->ycc_data_len, buf + idx, buf_len - idx); + if (ret < 0) + return -1; + idx += ret; + + extension_data_len = 0; + if (has_extension) { + ret = get_ue(&extension_data_len, buf + idx, buf_len - idx); + if (ret < 0) + return -1; + idx += ret; + } + + h->alpha_data_len = 0; + if (h->has_alpha) { + ret = get_ue(&h->alpha_data_len, buf + idx, buf_len - idx); + if (ret < 0) + return -1; + idx += ret; + } + + h->first_md = NULL; + if (has_extension) { + int ext_end; + + ext_end = idx + extension_data_len; + if (ext_end > buf_len) + return -1; +#ifndef EMSCRIPTEN + if (load_extensions) { + BPGExtensionData *md, **plast_md; + + plast_md = &h->first_md; + while (idx < ext_end) { + md = av_malloc(sizeof(BPGExtensionData)); + *plast_md = md; + plast_md = &md->next; + + ret = get_ue32(&md->tag, buf + idx, ext_end - idx); + if (ret < 0) + goto fail; + idx += ret; + + ret = get_ue(&md->buf_len, buf + idx, ext_end - idx); + if (ret < 0) + goto fail; + idx += ret; + + if (idx + md->buf_len > ext_end) { + fail: + bpg_decoder_free_extension_data(h->first_md); + return -1; + } + md->buf = av_malloc(md->buf_len); + memcpy(md->buf, buf + idx, md->buf_len); + idx += md->buf_len; + } + } else +#endif + { + /* skip extension data */ + idx += extension_data_len; + } + } + return idx; +} + +int bpg_decoder_decode(BPGDecoderContext *img, const uint8_t *buf, int buf_len) +{ + int idx, has_alpha, format, bit_depth, chroma_format_idc, color_space; + uint32_t width, height; + BPGHeaderData h_s, *h = &h_s; + + idx = bpg_decode_header(h, buf, buf_len, 0, img->keep_extension_data); + if (idx < 0) + return idx; + width = h->width; + height = h->height; + format = h->format; + has_alpha = h->has_alpha; + color_space = h->color_space; + bit_depth = h->bit_depth; + + img->w = width; + img->h = height; + img->format = format; + img->has_alpha = has_alpha; + img->premultiplied_alpha = h->premultiplied_alpha; + img->has_w_plane = h->has_w_plane; + img->limited_range = h->limited_range; + img->color_space = color_space; + img->bit_depth = bit_depth; + img->first_md = h->first_md; + + if (idx + h->ycc_data_len > buf_len) + goto fail; + chroma_format_idc = format; + img->frame = hevc_decode(buf + idx, h->ycc_data_len, + width, height, chroma_format_idc, bit_depth); + if (!img->frame) + goto fail; + idx += h->ycc_data_len; + + if (img->frame->width < img->w || img->frame->height < img->h) + goto fail; + + switch(img->frame->format) { + case AV_PIX_FMT_YUV420P16: + case AV_PIX_FMT_YUV420P: + if (format != BPG_FORMAT_420) + goto fail; + break; + case AV_PIX_FMT_YUV422P16: + case AV_PIX_FMT_YUV422P: + if (format != BPG_FORMAT_422) + goto fail; + break; + case AV_PIX_FMT_YUV444P16: + case AV_PIX_FMT_YUV444P: + if (format != BPG_FORMAT_444) + goto fail; + break; + case AV_PIX_FMT_GRAY16: + case AV_PIX_FMT_GRAY8: + if (format != BPG_FORMAT_GRAY) + goto fail; + break; + default: + goto fail; + } + + if (has_alpha) { + if (idx + h->alpha_data_len > buf_len) + goto fail; + img->alpha_frame = hevc_decode(buf + idx, h->alpha_data_len, + width, height, 0, bit_depth); + if (!img->alpha_frame) + goto fail; + idx += h->alpha_data_len; + } + + img->y = -1; + return 0; + + fail: + if (img->frame) + av_frame_free(&img->frame); + if (img->alpha_frame) + av_frame_free(&img->alpha_frame); + bpg_decoder_free_extension_data(img->first_md); + img->first_md = NULL; + return -1; +} + +void bpg_decoder_close(BPGDecoderContext *s) +{ + bpg_decoder_output_end(s); + if (s->frame) + av_frame_free(&s->frame); + if (s->alpha_frame) + av_frame_free(&s->alpha_frame); + bpg_decoder_free_extension_data(s->first_md); + av_free(s); +} + +void bpg_decoder_free_extension_data(BPGExtensionData *first_md) +{ +#ifndef EMSCRIPTEN + BPGExtensionData *md, *md_next; + + for(md = first_md; md != NULL; md = md_next) { + md_next = md->next; + av_free(md->buf); + av_free(md); + } +#endif +} + + +#ifndef EMSCRIPTEN +void bpg_decoder_keep_extension_data(BPGDecoderContext *s, int enable) +{ + s->keep_extension_data = enable; +} + +BPGExtensionData *bpg_decoder_get_extension_data(BPGDecoderContext *s) +{ + return s->first_md; +} + +int bpg_decoder_get_info_from_buf(BPGImageInfo *p, + BPGExtensionData **pfirst_md, + const uint8_t *buf, int buf_len) +{ + BPGHeaderData h_s, *h = &h_s; + int parse_extension; + + parse_extension = (pfirst_md != NULL); + if (bpg_decode_header(h, buf, buf_len, + !parse_extension, parse_extension) < 0) + return -1; + p->width = h->width; + p->height = h->height; + p->format = h->format; + p->has_alpha = h->has_alpha && !h->has_w_plane; + p->premultiplied_alpha = h->premultiplied_alpha; + p->has_w_plane = h->has_w_plane; + p->limited_range = h->limited_range; + p->color_space = h->color_space; + p->bit_depth = h->bit_depth; + if (pfirst_md) + *pfirst_md = h->first_md; + return 0; +} +#endif diff --git a/libbpg.h b/libbpg.h new file mode 100644 index 0000000..c8714ed --- /dev/null +++ b/libbpg.h @@ -0,0 +1,123 @@ +/* + * BPG decoder + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef _LIBBPG_H +#define _LIBBPG_H + +typedef struct BPGDecoderContext BPGDecoderContext; + +typedef enum { + BPG_FORMAT_GRAY, + BPG_FORMAT_420, + BPG_FORMAT_422, + BPG_FORMAT_444, +} BPGImageFormatEnum; + +typedef enum { + BPG_CS_YCbCr, + BPG_CS_RGB, + BPG_CS_YCgCo, + BPG_CS_YCbCr_BT709, + BPG_CS_YCbCr_BT2020, + + BPG_CS_COUNT, +} BPGColorSpaceEnum; + +typedef struct { + int width; + int height; + int format; /* see BPGImageFormatEnum */ + int has_alpha; /* TRUE if an alpha plane is present */ + int color_space; /* see BPGColorSpaceEnum */ + int bit_depth; + int premultiplied_alpha; /* TRUE if the color is alpha premultiplied */ + int has_w_plane; /* TRUE if a W plane is present (for CMYK encoding) */ + int limited_range; /* TRUE if limited range for the color */ +} BPGImageInfo; + +typedef enum { + BPG_EXTENSION_TAG_EXIF = 1, + BPG_EXTENSION_TAG_ICCP = 2, + BPG_EXTENSION_TAG_XMP = 3, + BPG_EXTENSION_TAG_THUMBNAIL = 4, +} BPGExtensionTagEnum; + +typedef struct BPGExtensionData { + BPGExtensionTagEnum tag; + uint32_t buf_len; + uint8_t *buf; + struct BPGExtensionData *next; +} BPGExtensionData; + +typedef enum { + BPG_OUTPUT_FORMAT_RGB24, + BPG_OUTPUT_FORMAT_RGBA32, /* not premultiplied alpha */ + BPG_OUTPUT_FORMAT_RGB48, + BPG_OUTPUT_FORMAT_RGBA64, /* not premultiplied alpha */ +} BPGDecoderOutputFormat; + +#define BPG_DECODER_INFO_BUF_SIZE 16 + +BPGDecoderContext *bpg_decoder_open(void); + +/* If enable is true, extension data are kept during the image + decoding and can be accessed after bpg_decoder_decode() with + bpg_decoder_get_extension(). By default, the extension data are + discarded. */ +void bpg_decoder_keep_extension_data(BPGDecoderContext *s, int enable); + +/* return 0 if 0K, < 0 if error */ +int bpg_decoder_decode(BPGDecoderContext *s, const uint8_t *buf, int buf_len); + +/* Return the first element of the extension data list */ +BPGExtensionData *bpg_decoder_get_extension_data(BPGDecoderContext *s); + +/* return 0 if 0K, < 0 if error */ +int bpg_decoder_get_info(BPGDecoderContext *s, BPGImageInfo *p); + +/* return 0 if 0K, < 0 if error */ +int bpg_decoder_start(BPGDecoderContext *s, BPGDecoderOutputFormat out_fmt); + +/* return 0 if 0K, < 0 if error */ +int bpg_decoder_get_line(BPGDecoderContext *s, void *buf); + +void bpg_decoder_close(BPGDecoderContext *s); + +/* only useful for low level access to the image data */ +uint8_t *bpg_decoder_get_data(BPGDecoderContext *s, int *pline_size, int plane); + +/* Get information from the start of the image data in 'buf' (at least + min(BPG_DECODER_INFO_BUF_SIZE, file_size) bytes must be given). + + If pfirst_md != NULL, the extension data are also parsed and the + first element of the list is returned in *pfirst_md. The list must + be freed with bpg_decoder_free_extension_data(). + + Return 0 if OK, < 0 if unrecognized data. */ +int bpg_decoder_get_info_from_buf(BPGImageInfo *p, + BPGExtensionData **pfirst_md, + const uint8_t *buf, int buf_len); +/* Free the extension data returned by bpg_decoder_get_info_from_buf() */ +void bpg_decoder_free_extension_data(BPGExtensionData *first_md); + +#endif /* _LIBBPG_H */ diff --git a/post.js b/post.js new file mode 100644 index 0000000..f7e3695 --- /dev/null +++ b/post.js @@ -0,0 +1,168 @@ +/* + * BPG Javascript decoder + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +window['BPGDecoder'] = function(ctx) { + this.ctx = ctx; + this['imageData'] = null; + this['onload'] = null; +} + +window['BPGDecoder'].prototype = { + +malloc: Module['cwrap']('malloc', 'number', [ 'number' ]), + +free: Module['cwrap']('free', 'void', [ 'number' ]), + +bpg_decoder_open: Module['cwrap']('bpg_decoder_open', 'number', [ ]), + +bpg_decoder_decode: Module['cwrap']('bpg_decoder_decode', 'number', [ 'number', 'array', 'number' ]), + +bpg_decoder_get_info: Module['cwrap']('bpg_decoder_get_info', 'number', [ 'number', 'number' ]), + +bpg_decoder_start: Module['cwrap']('bpg_decoder_start', 'number', [ 'number', 'number' ]), + +bpg_decoder_get_line: Module['cwrap']('bpg_decoder_get_line', 'number', [ 'number', 'number' ]), + +bpg_decoder_close: Module['cwrap']('bpg_decoder_close', 'void', [ 'number' ] ), + +load: function(url) +{ + var request = new XMLHttpRequest(); + var this1 = this; + + request.open("get", url, true); + request.responseType = "arraybuffer"; + request.onload = function(event) { + this1._onload(request, event); + }; + request.send(); +}, + +_onload: function(request, event) +{ + var data = request.response; + var array = new Uint8Array(data); + var img, w, h, img_info_buf, cimg, p0, rgba_line, w4; + var heap8, heap32, dst, v, i, y, func; + + // console.log("loaded " + data.byteLength + " bytes"); + + img = this.bpg_decoder_open(); + + if (this.bpg_decoder_decode(img, array, array.length) < 0) { + console.log("could not decode image"); + return; + } + + img_info_buf = this.malloc(9 * 4); + this.bpg_decoder_get_info(img, img_info_buf); + /* extract the image info */ + heap32 = Module['HEAPU32']; + w = heap32[img_info_buf >> 2]; + h = heap32[(img_info_buf + 4) >> 2]; + this.free(img_info_buf); + +// console.log("image " + w + " " + h); + + /* select RGBA32 output */ + this.bpg_decoder_start(img, 1); + + rgba_line = this.malloc(w * 4); + cimg = this.ctx.createImageData(w, h); + dst = cimg.data; + p0 = 0; + heap8 = Module['HEAPU8']; + w4 = w * 4; + for(y = 0; y < h; y++) { + this.bpg_decoder_get_line(img, rgba_line); + for(i = 0; i < w4; i = (i + 1) | 0) { + dst[p0] = heap8[(rgba_line + i) | 0] | 0; + p0 = (p0 + 1) | 0; + } + } + + this.free(rgba_line); + + this.bpg_decoder_close(img); + + this['imageData'] = cimg; + + if (this['onload']) + this['onload'](); +} + +}; + +window.onload = function() { + var i, n, el, tab, tab1, url, dec, canvas, id, style, ctx, dw, dh; + + /* put all images to load in a separate array */ + tab = document.images; + n = tab.length; + tab1 = []; + for(i = 0; i < n; i++) { + el = tab[i]; + url = el.src; + if (url.substr(-4,4).toLowerCase() == ".bpg") { + tab1[tab1.length] = el; + } + } + + /* change the tags to canvas */ + n = tab1.length; + for(i = 0; i < n; i++) { + el = tab1[i]; + url = el.src; + canvas = document.createElement("canvas"); + + if (el.id) + canvas.id = el.id; + if (el.className) + canvas.className = el.className; + + /* handle simple attribute cases to resize the canvas */ + dw = el.getAttribute("width") | 0; + if (dw) { + canvas.style.width = dw + "px"; + } + dh = el.getAttribute("height") | 0; + if (dh) { + canvas.style.height = dh + "px"; + } + + el.parentNode.replaceChild(canvas, el); + + ctx = canvas.getContext("2d"); + dec = new BPGDecoder(ctx); + dec.onload = (function(canvas, ctx) { + var imageData = this['imageData']; + /* resize the canvas to the image size */ + canvas.width = imageData.width; + canvas.height = imageData.height; + + /* draw the image */ + ctx.putImageData(imageData, 0, 0); + }).bind(dec, canvas, ctx); + dec.load(url); + } +}; diff --git a/tmalloc.c b/tmalloc.c new file mode 100644 index 0000000..84ffb6b --- /dev/null +++ b/tmalloc.c @@ -0,0 +1,314 @@ +/* + * Tiny malloc + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#ifndef MALLOC_TEST +#define NDEBUG +#endif +#include + +/* + * Note: only works for 32 bit pointers + */ +#define MALLOC_ALIGN 8 +#define MALLOC_BLOCK_SIZE 32 + +#define STATE_FREE 0xaa +#define STATE_ALLOCATED 0x55 + +struct list_head { + struct list_head *prev, *next; +}; + +#define list_entry(el, type, member) \ + ((type *)((uint8_t *)(el) - offsetof(type, member))) + +/* Note: the 'state' byte is stored just before the MemBlock header, + so at most 23 bytes can be allocated in a single block. */ +typedef struct MemBlock { + struct list_head link; + union { + uint8_t data[0] __attribute((aligned(MALLOC_ALIGN))); + struct list_head free_link; + } u; +} MemBlock; + +void *sbrk(intptr_t increment); + +/* Invariants: the last block is always a free block. The last free + block is always the last block. */ +static struct list_head free_list; +static struct list_head block_list; +static uint8_t *mem_top; + +/* insert 'el' after prev */ +static void list_add(struct list_head *el, struct list_head *prev) +{ + struct list_head *next = prev->next; + prev->next = el; + el->prev = prev; + el->next = next; + next->prev = el; +} + +static void list_del(struct list_head *el) +{ + struct list_head *prev, *next; + prev = el->prev; + next = el->next; + prev->next = next; + next->prev = prev; +} + +static size_t get_alloc_size(size_t size) +{ + size = offsetof(MemBlock, u.data) + size; + /* one more byte for the state byte from the next block */ + size = (size + MALLOC_BLOCK_SIZE) & ~(MALLOC_BLOCK_SIZE - 1); + return size; +} + +/* Note: this size includes the 'state' byte from the next block */ +static size_t get_block_size(MemBlock *p) +{ + uint8_t *end; + struct list_head *el; + el = p->link.next; + if (el == &block_list) + end = mem_top; + else + end = (uint8_t *)list_entry(el, MemBlock, link); + return end - (uint8_t *)p; +} + +static inline void set_block_state(MemBlock *p, int state) +{ + ((uint8_t *)p)[-1] = state; +} + +static inline int get_block_state(const MemBlock *p) +{ + return ((const uint8_t *)p)[-1]; +} + +void *malloc(size_t size) +{ + MemBlock *p, *p1; + struct list_head *el; + size_t block_size; + + if (size == 0 || size > (INT_MAX - 2 * MALLOC_BLOCK_SIZE)) + return NULL; + if (free_list.next == NULL) { + /* init */ + p = sbrk(MALLOC_BLOCK_SIZE * 2); + if (p == (void *)-1) + return NULL; + + mem_top = sbrk(0); + free_list.prev = free_list.next = &free_list; + block_list.prev = block_list.next = &block_list; + p++; + set_block_state(p, STATE_FREE); + list_add(&p->link, &block_list); + list_add(&p->u.free_link, &free_list); + } + + size = get_alloc_size(size); + el = free_list.next; + for(;;) { + p = list_entry(el, MemBlock, u.free_link); + assert(get_block_state(p) == STATE_FREE); + block_size = get_block_size(p); + if (size < block_size) { + goto done1; + } else if (el == free_list.prev) { + /* last free block: increase its size */ + if (sbrk(size + MALLOC_BLOCK_SIZE - block_size) == (void *)-1) + return NULL; + mem_top = sbrk(0); + done1: + p1 = (MemBlock *)((uint8_t *)p + size); + list_add(&p1->link, &p->link); + list_add(&p1->u.free_link, &p->u.free_link); + set_block_state(p1, STATE_FREE); + list_del(&p->u.free_link); + done: + set_block_state(p, STATE_ALLOCATED); + return p->u.data; + } else if (size == block_size) { + list_del(&p->u.free_link); + goto done; + } + el = el->next; + } +} + +void free(void *ptr) +{ + MemBlock *p, *p1; + struct list_head *el; + + if (!ptr) + return; + p = (MemBlock *)((uint8_t *)ptr - offsetof(MemBlock, u.data)); + assert(get_block_state(p) == STATE_ALLOCATED); + + /* mark as free */ + list_add(&p->u.free_link, &free_list); + set_block_state(p, STATE_FREE); + + /* merge with previous free block if possible */ + el = p->link.prev; + if (el != &block_list) { + p1 = list_entry(el, MemBlock, link); + if (get_block_state(p1) == STATE_FREE) { + list_del(&p->link); + list_del(&p->u.free_link); + p = p1; + } + } + /* merge with next block if possible */ + el = p->link.next; + if (el != &block_list) { + p1 = list_entry(el, MemBlock, link); + if (get_block_state(p1) == STATE_FREE) { + list_del(&p1->link); + /* keep p in the same position in free_list as p1 */ + list_del(&p->u.free_link); + list_add(&p->u.free_link, &p1->u.free_link); + list_del(&p1->u.free_link); + } + } +} + +void *realloc(void *ptr, size_t size) +{ + MemBlock *p; + void *ptr1; + size_t size1; + + if (ptr == NULL) { + return malloc(size); + } else if (size == 0) { + free(ptr); + return NULL; + } else { + p = (MemBlock *)((uint8_t *)ptr - offsetof(MemBlock, u.data)); + assert(get_block_state(p) == STATE_ALLOCATED); + ptr1 = malloc(size); + if (!ptr1) + return NULL; + /* Note: never the last block so it is valid */ + size1 = (uint8_t *)list_entry(p->link.next, MemBlock, link) - + p->u.data - 1; + if (size < size1) + size1 = size; + memcpy(ptr1, ptr, size1); + free(ptr); + return ptr1; + } +} + +#ifdef MALLOC_TEST +static void malloc_check(void) +{ + MemBlock *p; + struct list_head *el; + int state; + + for(el = block_list.next; el != &block_list; el = el->next) { + p = list_entry(el, MemBlock, link); + state = get_block_state(p); + assert(state == STATE_FREE || state == STATE_ALLOCATED); + if (el->next != &block_list) + assert(el->next > el); + } + for(el = free_list.next; el != &free_list; el = el->next) { + p = list_entry(el, MemBlock, u.free_link); + assert(get_block_state(p) == STATE_FREE); + } + + /* check invariant */ + el = free_list.prev; + if (el != &free_list) { + p = list_entry(el, MemBlock, u.free_link); + assert(&p->link == block_list.prev); + } +} + +static void malloc_dump(void) +{ + MemBlock *p; + struct list_head *el; + + printf("blocks:\n"); + for(el = block_list.next; el != &block_list; el = el->next) { + p = list_entry(el, MemBlock, link); + printf("block: %p next=%p free=%d size=%u\n", p, p->link.next, + get_block_state(p) == STATE_FREE, + (unsigned int)get_block_size(p)); + } + printf("free list:\n"); + for(el = free_list.next; el != &free_list; el = el->next) { + p = list_entry(el, MemBlock, u.free_link); + printf("block: %p size=%u\n", p, (unsigned int)get_block_size(p)); + } +} + +int main(int argc, char **argv) +{ + int i, n, j, size; + void **tab; + + n = 100; + tab = malloc(sizeof(void *) * n); + memset(tab, 0, n * sizeof(void *)); + + for(i = 0; i < n * 1000; i++) { + j = random() % n; + + free(tab[j]); + + malloc_check(); + + size = random() % 500; + tab[j] = malloc(size); + memset(tab[j], 0x11, size); + + malloc_check(); + } + + malloc_dump(); + + for(i = 0; i < n; i++) { + free(tab[i]); + } + return 0; +} +#endif diff --git a/x265_glue.c b/x265_glue.c new file mode 100644 index 0000000..484d80f --- /dev/null +++ b/x265_glue.c @@ -0,0 +1,166 @@ +/* + * x265 encoder front-end + * + * Copyright (c) 2014 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include + +#include "bpgenc.h" + +#include "x265.h" + +int x265_encode_picture(uint8_t **pbuf, Image *img, + const HEVCEncodeParams *params) +{ + x265_encoder *enc; + x265_param *p; + x265_picture *pic, *pic_in; + x265_nal *p_nal; + int buf_len, idx, c_count, i, ret, pic_count; + uint32_t nal_count; + uint8_t *buf; + int preset_index; + const char *preset; + + if (img->bit_depth != x265_max_bit_depth) { + fprintf(stderr, "x265 is compiled to support only %d bit depth. Use the '-b %d' option to force the bit depth.\n", + x265_max_bit_depth, x265_max_bit_depth); + return -1; + } + if (img->format == BPG_FORMAT_GRAY) { + fprintf(stderr, "x265 does not support monochrome (or alpha) data yet. Plase use the jctvc encoder.\n"); + return -1; + } + + p = x265_param_alloc(); + + preset_index = params->compress_level; /* 9 is placebo */ + + preset = x265_preset_names[preset_index]; + if (params->verbose) + printf("Using x265 preset: %s\n", preset); + + x265_param_default_preset(p, preset, "ssim"); + + p->bRepeatHeaders = 1; + p->decodedPictureHashSEI = params->sei_decoded_picture_hash; + p->sourceWidth = img->w; + p->sourceHeight = img->h; + switch(img->format) { + case BPG_FORMAT_GRAY: + p->internalCsp = X265_CSP_I400; + break; + case BPG_FORMAT_420: + p->internalCsp = X265_CSP_I420; + break; + case BPG_FORMAT_422: + p->internalCsp = X265_CSP_I422; + break; + case BPG_FORMAT_444: + p->internalCsp = X265_CSP_I444; + break; + default: + abort(); + } + p->keyframeMax = 1; /* only I frames */ + p->internalBitDepth = img->bit_depth; + p->bEmitInfoSEI = 0; + if (params->verbose) + p->logLevel = X265_LOG_INFO; + else + p->logLevel = X265_LOG_NONE; + + /* dummy frame rate */ + p->fpsNum = 25; + p->fpsDenom = 1; + p->totalFrames = 1; + + p->rc.rateControlMode = X265_RC_CQP; + /* XXX: why do we need this offset to match the JCTVC quality ? */ + if (img->bit_depth == 10) + p->rc.qp = params->qp + 7; + else + p->rc.qp = params->qp + 1; + p->bLossless = params->lossless; + + enc = x265_encoder_open(p); + + pic = x265_picture_alloc(); + x265_picture_init(p, pic); + + if (img->format == BPG_FORMAT_GRAY) + c_count = 1; + else + c_count = 3; + for(i = 0; i < c_count; i++) { + pic->planes[i] = img->data[i]; + pic->stride[i] = img->linesize[i]; + } + pic->bitDepth = img->bit_depth; + pic->colorSpace = p->internalCsp; + + pic_count = 0; + for(;;) { + if (pic_count == 0) + pic_in = pic; + else + pic_in = NULL; + ret = x265_encoder_encode(enc, &p_nal, &nal_count, pic_in, NULL); + if (ret < 0) + goto fail; + if (ret == 1) + break; + pic_count++; + } + + buf_len = 0; + for(i = 0; i < nal_count; i++) { + buf_len += p_nal[i].sizeBytes; + } + // printf("nal_count=%d buf_len=%d\n", nal_count, buf_len); + + buf = malloc(buf_len); + idx = 0; + for(i = 0; i < nal_count; i++) { + memcpy(buf + idx, p_nal[i].payload, p_nal[i].sizeBytes); + idx += p_nal[i].sizeBytes; + } + + x265_encoder_close(enc); + + x265_param_free(p); + + x265_picture_free(pic); + + *pbuf = buf; + return buf_len; + fail: + x265_encoder_close(enc); + + x265_param_free(p); + x265_picture_free(pic); + *pbuf = NULL; + return -1; +}