Projects
Staging
libde265
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 22
View file
libde265.changes
Changed
@@ -1,4 +1,47 @@ ------------------------------------------------------------------- +Tue Sep 15 10:26:14 UTC 2026 - Bjørn Lie <bjorn.lie@gmail.com> + +- Update to version 1.1.3: + + This release completes high bit depth decoding (up to 16 bit) + and repairs cross-component prediction, which had corrupted + 4:4:4 Range Extensions streams since v1.0.17. It is ABI- and + API-compatible with v1.1.2 and a drop-in replacement; no + functions or enum values were added. + + High bit depth decoding: + - Inter prediction above 12 bit was wrong from the first P/B + picture on. The fractional sample interpolation used shift1 = + BitDepth-8 instead of the Range Extensions' Min(4, + BitDepth-8), and the intermediate prediction samples were + kept in int16_t although they need max(14, BitDepth+2) bits. + The 16-bit kernels are now templated on the intermediate + sample type and use int32_t above 12 bit; 8- to 12-bit + streams are unaffected and keep their SSE paths. Explicit + weighted bi-prediction was broken in a second way: the + shortcut for identical motion vectors checked + weighted_pred_flag, which governs P slices, instead of + weighted_bipred_flag. + - Together with the fixes in v1.1.1 and v1.1.2 this completes + high bit depth support. Output is bit-exact against the HM 18 + reference decoder at 10, 12, 13, 14 and 16 bit, for mixed + luma/chroma bit depths and for 4:2:2, 4:4:4 and 4:0:0. Above + 12 bit motion compensation runs the scalar kernels; 8-bit + performance is unchanged. + + Range Extensions: + - Cross-component prediction corrupted every chroma block it + was applied to, a regression since v1.0.17. A cast added to + silence undefined behaviour on a left shift turned the + following arithmetic shift into a logical one, so every + negative luma residual became a large positive value. This + affects 4:4:4 streams only, but at every bit depth including + 8 bit. + - cabac_bypass_alignment_enabled_flag was parsed and then + ignored, so a stream using it desynchronized CABAC and + decoded to garbage without any diagnostic. It is now + implemented as specified in 9.3.4.3.6, and was the last Range + Extensions tool still missing. Both fixes are bit-exact + against HM 18. + +------------------------------------------------------------------- Thu Sep 3 06:04:55 UTC 2026 - Bjørn Lie <zaitor@opensuse.org> - Update to version 1.1.2:
View file
libde265.spec
Changed
@@ -18,7 +18,7 @@ %define so_ver 0 Name: libde265 -Version: 1.1.2 +Version: 1.1.3 Release: 0 Summary: Open H.265 video codec implementation License: LGPL-3.0-only
View file
libde265-1.1.2.tar.gz/CMakeLists.txt -> libde265-1.1.3.tar.gz/CMakeLists.txt
Changed
@@ -2,7 +2,7 @@ project (libde265 LANGUAGES C CXX - VERSION 1.1.2 + VERSION 1.1.3 ) # Auto-compute BCD-encoded numeric version from project version. @@ -35,7 +35,7 @@ # Programs linked against libde265.so.0 will work with any libde265.so.0.x.y. # set(DE265_SOVERSION 0) -set(DE265_LIBRARY_VERSION "0.2.2") +set(DE265_LIBRARY_VERSION "0.2.3") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)
View file
libde265-1.1.2.tar.gz/README.md -> libde265-1.1.3.tar.gz/README.md
Changed
@@ -8,9 +8,13 @@ It is written from scratch and has a plain C API to enable a simple integration into other software. -libde265 supports WPP and tile-based multithreading and includes SSE optimizations. -The decoder includes all features of the Main profile and correctly decodes almost all -conformance streams (see wiki page(https://github.com/strukturag/libde265/wiki/Decoder-conformance)). +libde265 supports WPP and tile-based multithreading and includes SSE, AVX2 and AVX-512 +optimizations. +The decoder includes all features of the Main profile, and it supports Main 10 and the +Range Extensions: bit depths from 8 to 16 bit (independently for luma and chroma), the +4:2:0, 4:2:2, 4:4:4 and monochrome chroma formats, and the Range Extensions coding tools. +It correctly decodes almost all conformance streams (see +wiki page(https://github.com/strukturag/libde265/wiki/Decoder-conformance)). A list of supported features are available in the wiki(https://github.com/strukturag/libde265/wiki/Supported-decoding-features).
View file
libde265-1.1.2.tar.gz/libde265/acceleration.h -> libde265-1.1.3.tar.gz/libde265/acceleration.h
Changed
@@ -26,6 +26,12 @@ #include <assert.h> +// Highest bit depth at which the intermediate motion-compensation samples +// (predSamplesLX, spec 8.5.3.3.3) still fit into int16_t. Above it, the +// "_16_32" kernels with int32_t intermediates are used. +constexpr int MC_MAX_BIT_DEPTH_INT16 = 12; + + struct acceleration_functions { void (*put_weighted_pred_avg_8)(uint8_t *_dst, ptrdiff_t dststride, @@ -64,22 +70,63 @@ int w1,int o1, int w2,int o2, int log2WD, int bit_depth); + // --- BitDepth > MC_MAX_BIT_DEPTH_INT16 --- + // The intermediate prediction samples (predSamplesLX, spec 8.5.3.3.3) have + // max(14, BitDepth+2) bits plus the overshoot of the interpolation filters, + // so above 12 bits they do not fit into int16_t anymore. These variants of the + // 16-bit pixel kernels take int32_t intermediates instead. + + void (*put_weighted_pred_avg_16_32)(uint16_t *_dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, int bit_depth); + + void (*put_unweighted_pred_16_32)(uint16_t *_dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, int bit_depth); + + void (*put_weighted_pred_16_32)(uint16_t *_dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, + int w,int o,int log2WD, int bit_depth); + void (*put_weighted_bipred_16_32)(uint16_t *_dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, + int w1,int o1, int w2,int o2, int log2WD, int bit_depth); + + + // Dispatch on bit depth; the int32_t overloads are for BitDepth > MC_MAX_BIT_DEPTH_INT16 only. + void put_weighted_pred_avg(void *_dst, ptrdiff_t dststride, const int16_t *src1, const int16_t *src2, ptrdiff_t srcstride, int width, int height, int bit_depth) const; + void put_weighted_pred_avg(void *_dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, int bit_depth) const; void put_unweighted_pred(void *_dst, ptrdiff_t dststride, const int16_t *src, ptrdiff_t srcstride, int width, int height, int bit_depth) const; + void put_unweighted_pred(void *_dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, int bit_depth) const; void put_weighted_pred(void *_dst, ptrdiff_t dststride, const int16_t *src, ptrdiff_t srcstride, int width, int height, int w,int o,int log2WD, int bit_depth) const; + void put_weighted_pred(void *_dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, + int w,int o,int log2WD, int bit_depth) const; + void put_weighted_bipred(void *_dst, ptrdiff_t dststride, const int16_t *src1, const int16_t *src2, ptrdiff_t srcstride, int width, int height, int w1,int o1, int w2,int o2, int log2WD, int bit_depth) const; + void put_weighted_bipred(void *_dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, + int w1,int o1, int w2,int o2, int log2WD, int bit_depth) const; @@ -120,6 +167,31 @@ int16_t* mcbuffer, int bit_depth); + // --- BitDepth > MC_MAX_BIT_DEPTH_INT16: 16-bit pixels, int32_t intermediates (see above) --- + + void (*put_hevc_epel_16_32)(int32_t *dst, ptrdiff_t dststride, + const uint16_t *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth); + void (*put_hevc_epel_h_16_32)(int32_t *dst, ptrdiff_t dststride, + const uint16_t *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth); + void (*put_hevc_epel_v_16_32)(int32_t *dst, ptrdiff_t dststride, + const uint16_t *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth); + void (*put_hevc_epel_hv_16_32)(int32_t *dst, ptrdiff_t dststride, + const uint16_t *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth); + + // One generic kernel for all fractional positions (including full-sample), + // since this path is not performance critical and per-position copies of + // the filter would cost ~50 KB of code. + void (*put_hevc_qpel_16_32)(int32_t *dst, ptrdiff_t dststride, + const uint16_t *src, ptrdiff_t srcstride, int width, int height, + int32_t* mcbuffer, int xFrac, int yFrac, int bit_depth); + + + // Dispatch on bit depth; the int32_t overloads are for BitDepth > MC_MAX_BIT_DEPTH_INT16 only. + void put_hevc_epel(int16_t *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, int width, int height, int mx, int my, int16_t* mcbuffer, int bit_depth) const; @@ -137,6 +209,23 @@ const void *src, ptrdiff_t srcstride, int width, int height, int16_t* mcbuffer, int dX,int dY, int bit_depth) const; + void put_hevc_epel(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const; + void put_hevc_epel_h(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const; + void put_hevc_epel_v(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const; + void put_hevc_epel_hv(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const; + + void put_hevc_qpel(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int32_t* mcbuffer, int dX,int dY, int bit_depth) const; + // --- inverse transforms --- @@ -368,6 +457,88 @@ put_hevc_qpel_16dXdY(dst,dststride,(const uint16_t*)src,srcstride,width,height,mcbuffer, bit_depth); } + +// --- BitDepth > MC_MAX_BIT_DEPTH_INT16: int32_t intermediates, always 16-bit pixels --- + +inline void acceleration_functions::put_weighted_pred_avg(void* _dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, int bit_depth) const +{ + assert(bit_depth > 8); + put_weighted_pred_avg_16_32((uint16_t*)_dst,dststride,src1,src2,srcstride,width,height,bit_depth); +} + + +inline void acceleration_functions::put_unweighted_pred(void* _dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, int bit_depth) const +{ + assert(bit_depth > 8); + put_unweighted_pred_16_32((uint16_t*)_dst,dststride,src,srcstride,width,height,bit_depth); +} + + +inline void acceleration_functions::put_weighted_pred(void* _dst, ptrdiff_t dststride, + const int32_t *src, ptrdiff_t srcstride, + int width, int height, + int w,int o,int log2WD, int bit_depth) const +{ + assert(bit_depth > 8); + put_weighted_pred_16_32((uint16_t*)_dst,dststride,src,srcstride,width,height,w,o,log2WD,bit_depth); +} + + +inline void acceleration_functions::put_weighted_bipred(void* _dst, ptrdiff_t dststride, + const int32_t *src1, const int32_t *src2, ptrdiff_t srcstride, + int width, int height, + int w1,int o1, int w2,int o2, int log2WD, int bit_depth) const +{ + assert(bit_depth > 8); + put_weighted_bipred_16_32((uint16_t*)_dst,dststride,src1,src2,srcstride, width,height, w1,o1,w2,o2,log2WD,bit_depth); +} + + +inline void acceleration_functions::put_hevc_epel(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const +{ + assert(bit_depth > 8); + put_hevc_epel_16_32(dst,dststride,(const uint16_t*)src,srcstride,width,height,mx,my,mcbuffer, bit_depth); +} + +inline void acceleration_functions::put_hevc_epel_h(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const +{ + assert(bit_depth > 8); + put_hevc_epel_h_16_32(dst,dststride,(const uint16_t*)src,srcstride,width,height,mx,my,mcbuffer,bit_depth); +} + +inline void acceleration_functions::put_hevc_epel_v(int32_t *dst, ptrdiff_t dststride, + const void *src, ptrdiff_t srcstride, int width, int height, + int mx, int my, int32_t* mcbuffer, int bit_depth) const +{ + assert(bit_depth > 8); + put_hevc_epel_v_16_32(dst,dststride,(const uint16_t*)src,srcstride,width,height,mx,my,mcbuffer, bit_depth);
View file
libde265-1.1.2.tar.gz/libde265/cabac.cc -> libde265-1.1.3.tar.gz/libde265/cabac.cc
Changed
@@ -371,6 +371,17 @@ // When we read past the end of the bitstream (which should only happen on faulty bitstreams), // we will eventually only return zeros. +/* (9.3.4.3.6) Alignment process prior to aligned bypass decoding. Invoked before the + bypass-coded coeff_sign_flag / coeff_abs_level_remaining of a sub-block carrying escape + data when cabac_bypass_alignment_enabled_flag is set. Bypass decoding leaves + ivlCurrRange untouched, so a single call covers the whole run of bypass bins after it. +*/ +void CABAC_decoder::align_bypass() +{ + range = 256; +} + + int CABAC_decoder::decode_bypass() { #ifdef DE265_CABAC_ASM_X86_64
View file
libde265-1.1.2.tar.gz/libde265/cabac.h -> libde265-1.1.3.tar.gz/libde265/cabac.h
Changed
@@ -34,6 +34,7 @@ int decode_term_bit(); int decode_bypass(); + void align_bypass(); int decode_TU_bypass(int cMax); uint32_t decode_FL_bypass(int nBits); int decode_TR_bypass(int cRiceParam, int cTRMax);
View file
libde265-1.1.2.tar.gz/libde265/de265.h -> libde265-1.1.3.tar.gz/libde265/de265.h
Changed
@@ -352,6 +352,25 @@ int visible_height; // convenience, height - crop_top - crop_bottom } de265_image_spec; +/* Custom image buffer allocation. + + get_buffer() has to provide the image planes by calling de265_set_image_plane() + for each of them. The buffers have to be large enough for the image described by + 'spec', taking spec->alignment into account when computing the stride, plus at + least 16 trailing bytes beyond the last row. The SIMD code processes whole vectors + and may read up to a vector past the pixels it actually uses, so a plane allocated + with no slack is read out of bounds. Allocate the trailing bytes unconditionally; + whether they are touched depends on which SIMD paths libde265 was built with and + on the CPU it runs on. + + The memory handed back has to be zero-initialized (or otherwise fully initialized). + libde265 does not clear buffers obtained from get_buffer(); only the built-in + allocator returned by de265_get_default_image_allocation_functions() clears them + itself. If an allocator returns uninitialized memory, any part of an image that the + decoder does not write -- for example a picture that a corrupted stream covers only + partially with slices -- shows up in the decoded output, exposing whatever the + application previously kept in that memory. +*/ typedef struct de265_image_allocation { int (*get_buffer)(de265_decoder_context* ctx, // first parameter deprecated
View file
libde265-1.1.2.tar.gz/libde265/decctx.cc -> libde265-1.1.3.tar.gz/libde265/decctx.cc
Changed
@@ -25,6 +25,7 @@ #include "deblock.h" #include <algorithm> +#include <utility> #include <string.h> #include <assert.h> #include <stdlib.h> @@ -92,7 +93,9 @@ slice_unit::~slice_unit() { - ctx->nal_parser.free_NAL_unit(nal); + // Return our NAL to the reuse pool. (Letting the unique_ptr delete it would be + // memory-safe too, but would bypass pooling.) + ctx->nal_parser.free_NAL_unit(std::move(nal)); if (thread_contexts) { delete thread_contexts; @@ -503,7 +506,7 @@ } -de265_error decoder_context::read_slice_NAL(bitreader& reader, NAL_unit* nal, nal_header& nal_hdr) +de265_error decoder_context::read_slice_NAL(bitreader& reader, std::unique_ptr<NAL_unit> nal, nal_header& nal_hdr) { logdebug(LogHeaders,"---> read slice segment header\n"); @@ -515,7 +518,7 @@ de265_error err = shdr->read(&reader,this, &continueDecoding); if (!continueDecoding) { if (img) { img->integrity = INTEGRITY_NOT_DECODED; } - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); delete shdr; return err; } @@ -528,7 +531,7 @@ if (process_slice_segment_header(shdr, &err, nal->pts, &nal_hdr, nal->user_data) == false) { if (img!=nullptr) img->integrity = INTEGRITY_NOT_DECODED; - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); delete shdr; return err; } @@ -545,7 +548,7 @@ headerLength); if (skipped > shdr->entry_point_offseti) { add_warning(DE265_WARNING_SLICEHEADER_INVALID, false); - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); delete shdr; return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE; } @@ -585,7 +588,7 @@ previous_slice_header = shdr; slice_unit* sliceunit = new slice_unit(this); - sliceunit->nal = nal; + sliceunit->nal = std::move(nal); sliceunit->shdr = shdr; sliceunit->reader = reader; @@ -595,7 +598,7 @@ image_units.back()->slice_units.push_back(sliceunit); } else { - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); delete shdr; } @@ -1133,7 +1136,13 @@ } -de265_error decoder_context::decode_NAL(NAL_unit* nal) +// Ownership: decode_NAL() receives the NAL by moved-in unique_ptr and releases +// it on every return path. Parameter-set, SEI and discarded NALs are returned to +// the pool directly here; slice NALs are moved into read_slice_NAL(), which +// either releases the NAL or moves it into a slice_unit that owns it for the rest +// of the image_unit's lifetime. Because ownership is a unique_ptr, the NAL cannot +// be released twice. +de265_error decoder_context::decode_NAL(std::unique_ptr<NAL_unit> nal) { //return decode_NAL_OLD(nal); @@ -1146,7 +1155,7 @@ nal_header nal_hdr; err = nal_hdr.read(&reader); if (err != DE265_OK) { - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); return err; } ctx->process_nal_hdr(&nal_hdr); @@ -1154,7 +1163,7 @@ if (nal_hdr.nuh_layer_id > 0) { // Discard all NAL units with nuh_layer_id > 0 // These will have to be handled by an SHVC decoder. - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); return DE265_OK; } @@ -1176,43 +1185,43 @@ //printf("hTid: %d\n", current_HighestTid); if (nal_hdr.nuh_temporal_id > current_HighestTid) { - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); return DE265_OK; } if (nal_hdr.nal_unit_type<32) { - err = read_slice_NAL(reader, nal, nal_hdr); + err = read_slice_NAL(reader, std::move(nal), nal_hdr); } else switch (nal_hdr.nal_unit_type) { case NAL_UNIT_VPS_NUT: err = read_vps_NAL(reader); - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; case NAL_UNIT_SPS_NUT: err = read_sps_NAL(reader); - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; case NAL_UNIT_PPS_NUT: err = read_pps_NAL(reader); - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; case NAL_UNIT_PREFIX_SEI_NUT: case NAL_UNIT_SUFFIX_SEI_NUT: err = read_sei_NAL(reader, nal_hdr.nal_unit_type==NAL_UNIT_SUFFIX_SEI_NUT); - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; case NAL_UNIT_EOS_NUT: ctx->FirstAfterEndOfSequenceNAL = true; - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; default: - nal_parser.free_NAL_unit(nal); + nal_parser.free_NAL_unit(std::move(nal)); break; } @@ -1268,10 +1277,13 @@ bool did_work = false; if (ctx->nal_parser.get_NAL_queue_length()) { // number_of_NAL_units_pending()) { - NAL_unit* nal = ctx->nal_parser.pop_from_NAL_queue(); + std::unique_ptr<NAL_unit> nal = ctx->nal_parser.pop_from_NAL_queue(); assert(nal); - err = ctx->decode_NAL(nal); - // ctx->nal_parser.free_NAL_unit(nal); TODO: do not free NAL with new loop + + // Ownership of the dequeued NAL moves into decode_NAL(), which releases it on + // every path (directly, or via a slice_unit that returns it to the pool when + // the image_unit is destroyed). Nothing to free here. + err = ctx->decode_NAL(std::move(nal)); did_work=true; } else if (ctx->nal_parser.is_end_of_frame() == true &&
View file
libde265-1.1.2.tar.gz/libde265/decctx.h -> libde265-1.1.3.tar.gz/libde265/decctx.h
Changed
@@ -145,7 +145,7 @@ slice_unit(decoder_context* decctx); ~slice_unit(); - NAL_unit* nal; // we are the owner + std::unique_ptr<NAL_unit> nal; // we are the owner slice_segment_header* shdr; // not the owner (de265_image is owner) bitreader reader; @@ -333,7 +333,7 @@ uint8_t get_nal_unit_type() const { return nal_unit_type; } bool get_RapPicFlag() const { return RapPicFlag; } - de265_error decode_NAL(NAL_unit* nal); + de265_error decode_NAL(std::unique_ptr<NAL_unit> nal); de265_error decode(int* more); de265_error decode_some(bool* did_work); @@ -405,7 +405,7 @@ de265_error read_pps_NAL(bitreader&); de265_error read_sei_NAL(bitreader& reader, bool suffix); de265_error read_eos_NAL(bitreader& reader); - de265_error read_slice_NAL(bitreader&, NAL_unit* nal, nal_header& nal_hdr); + de265_error read_slice_NAL(bitreader&, std::unique_ptr<NAL_unit> nal, nal_header& nal_hdr); private: // --- internal data ---
View file
libde265-1.1.2.tar.gz/libde265/fallback-motion.cc -> libde265-1.1.3.tar.gz/libde265/fallback-motion.cc
Changed
@@ -28,6 +28,7 @@ #endif #include <assert.h> +#include <algorithm> void put_unweighted_pred_8_fallback(uint8_t *dst, ptrdiff_t dststride, @@ -161,8 +162,13 @@ +// The 16-bit pixel kernels are templates on the type of the intermediate +// prediction samples (predSamplesLX in the spec): int16_t for BitDepth <= 12, +// int32_t above (see acceleration.h). + +template <class inter_t> void put_unweighted_pred_16_fallback(uint16_t *dst, ptrdiff_t dststride, - const int16_t *src, ptrdiff_t srcstride, + const inter_t *src, ptrdiff_t srcstride, int width, int height, int bit_depth) { // shift1 per HEVC v2 (10/2014) spec 8.5.3.3.4.2: Max(2, 14 - BitDepth). @@ -174,7 +180,7 @@ assert((width&1)==0); for (int y=0;y<height;y++) { - const int16_t* in = &srcy*srcstride; + const inter_t* in = &srcy*srcstride; uint16_t* out = &dsty*dststride; for (int x=0;x<width;x+=2) { @@ -185,19 +191,23 @@ } } +template void put_unweighted_pred_16_fallback<int16_t>(uint16_t*, ptrdiff_t, const int16_t*, ptrdiff_t, int, int, int); +template void put_unweighted_pred_16_fallback<int32_t>(uint16_t*, ptrdiff_t, const int32_t*, ptrdiff_t, int, int, int); + #include <stdlib.h> +template <class inter_t> void put_weighted_pred_16_fallback(uint16_t *dst, ptrdiff_t dststride, - const int16_t *src, ptrdiff_t srcstride, + const inter_t *src, ptrdiff_t srcstride, int width, int height, int w,int o,int log2WD, int bit_depth) { - assert(log2WD>=1); // TODO + assert(log2WD>=1); // log2WD = log2_weight_denom + Max(2, 14-BitDepth) >= 2 const int rnd = (1<<(log2WD-1)); for (int y=0;y<height;y++) { - const int16_t* in = &srcy*srcstride; + const inter_t* in = &srcy*srcstride; uint16_t* out = &dsty*dststride; for (int x=0;x<width;x++) { @@ -207,18 +217,24 @@ } } +template void put_weighted_pred_16_fallback<int16_t>(uint16_t*, ptrdiff_t, const int16_t*, ptrdiff_t, int, int, int, int, int, int); +template void put_weighted_pred_16_fallback<int32_t>(uint16_t*, ptrdiff_t, const int32_t*, ptrdiff_t, int, int, int, int, int, int); + +template <class inter_t> void put_weighted_bipred_16_fallback(uint16_t *dst, ptrdiff_t dststride, - const int16_t *src1, const int16_t *src2, ptrdiff_t srcstride, + const inter_t *src1, const inter_t *src2, ptrdiff_t srcstride, int width, int height, int w1,int o1, int w2,int o2, int log2WD, int bit_depth) { - assert(log2WD>=1); // TODO + assert(log2WD>=1); // log2WD = log2_weight_denom + Max(2, 14-BitDepth) >= 2 + // Worst case at BitDepth 16 (int32_t intermediates): |predSample| < 2^20, |w| <= 255, + // |o1+o2+1| <= 2^16, log2WD <= 9 -> the sum stays below 2^29 and fits into int. const int rnd = static_cast<int>(static_cast<unsigned int>(o1+o2+1) << log2WD); for (int y=0;y<height;y++) { - const int16_t* in1 = &src1y*srcstride; - const int16_t* in2 = &src2y*srcstride; + const inter_t* in1 = &src1y*srcstride; + const inter_t* in2 = &src2y*srcstride; uint16_t* out = &dsty*dststride; for (int x=0;x<width;x++) { @@ -228,9 +244,13 @@ } } +template void put_weighted_bipred_16_fallback<int16_t>(uint16_t*, ptrdiff_t, const int16_t*, const int16_t*, ptrdiff_t, int, int, int, int, int, int, int, int); +template void put_weighted_bipred_16_fallback<int32_t>(uint16_t*, ptrdiff_t, const int32_t*, const int32_t*, ptrdiff_t, int, int, int, int, int, int, int, int); + +template <class inter_t> void put_weighted_pred_avg_16_fallback(uint16_t *dst, ptrdiff_t dststride, - const int16_t *src1, const int16_t *src2, + const inter_t *src1, const inter_t *src2, ptrdiff_t srcstride, int width, int height, int bit_depth) { @@ -243,8 +263,8 @@ assert((width&1)==0); for (int y=0;y<height;y++) { - const int16_t* in1 = &src1y*srcstride; - const int16_t* in2 = &src2y*srcstride; + const inter_t* in1 = &src1y*srcstride; + const inter_t* in2 = &src2y*srcstride; uint16_t* out = &dsty*dststride; for (int x=0;x<width;x+=2) { @@ -255,6 +275,9 @@ } } +template void put_weighted_pred_avg_16_fallback<int16_t>(uint16_t*, ptrdiff_t, const int16_t*, const int16_t*, ptrdiff_t, int, int, int); +template void put_weighted_pred_avg_16_fallback<int32_t>(uint16_t*, ptrdiff_t, const int32_t*, const int32_t*, ptrdiff_t, int, int, int); + @@ -279,10 +302,11 @@ } -void put_epel_16_fallback(int16_t *out, ptrdiff_t out_stride, +template <class inter_t> +void put_epel_16_fallback(inter_t *out, ptrdiff_t out_stride, const uint16_t *src, ptrdiff_t src_stride, int width, int height, - int mx, int my, int16_t* mcbuffer, int bit_depth) + int mx, int my, inter_t* mcbuffer, int bit_depth) { // shift3 per HEVC v2 (10/2014) spec 8.5.3.3.3.3 (chroma): Max(2, 14 - BitDepth). // The Max() was added with the Range Extensions in v2 to handle BitDepth up to 16; @@ -290,7 +314,7 @@ int shift3 = std::max(2, 14 - bit_depth); for (int y=0;y<height;y++) { - int16_t* o = &outy*out_stride; + inter_t* o = &outy*out_stride; const uint16_t* i = &srcy*src_stride; for (int x=0;x<width;x++) { @@ -301,14 +325,20 @@ } } +template void put_epel_16_fallback<int16_t>(int16_t*, ptrdiff_t, const uint16_t*, ptrdiff_t, int, int, int, int, int16_t*, int); +template void put_epel_16_fallback<int32_t>(int32_t*, ptrdiff_t, const uint16_t*, ptrdiff_t, int, int, int, int, int32_t*, int); -template <class pixel_t> -void put_epel_hv_fallback(int16_t *dst, ptrdiff_t dst_stride, + +template <class pixel_t, class inter_t> +void put_epel_hv_fallback(inter_t *dst, ptrdiff_t dst_stride, const pixel_t *src, ptrdiff_t src_stride, int nPbWC, int nPbHC, - int xFracC, int yFracC, int16_t* mcbuffer, int bit_depth) + int xFracC, int yFracC, inter_t* mcbuffer, int bit_depth) { - const int shift1 = bit_depth-8; + // shift1 per HEVC v2 (10/2014) spec 8.5.3.3.3.3 (chroma): Min(4, BitDepth - 8). + // The Min() was added with the Range Extensions in v2 for BitDepth > 12: the + // intermediate samples then keep BitDepth+2 bits instead of 14 (see shift3). + const int shift1 = std::min(4, bit_depth-8); const int shift2 = 6; //const int shift3 = 6; @@ -320,7 +350,7 @@ int nPbH_extra = extra_top + nPbHC + extra_bottom; - int16_t* tmp2buf = (int16_t*)alloca( nPbWC * nPbH_extra * sizeof(int16_t) ); + inter_t* tmp2buf = (inter_t*)alloca( nPbWC * nPbH_extra * sizeof(inter_t) ); /* int nPbW_extra = extra_left + nPbWC + extra_right; @@ -351,7 +381,7 @@ const pixel_t* p = &srcy*src_stride - extra_left; for (int x=0;x<nPbWC;x++) { - int16_t v; + int v; switch (xFracC) { case 0: v = p1; break; case 1: v = (-2*p0+58*p1+10*p2-2*p3)>>shift1; break; @@ -379,10 +409,10 @@ int vshift = (xFracC==0 ? shift1 : shift2); for (int x=0;x<nPbWC;x++) { - int16_t* p = &tmp2bufx*nPbH_extra; + inter_t* p = &tmp2bufx*nPbH_extra; for (int y=0;y<nPbHC;y++) { - int16_t v; + int v;
View file
libde265-1.1.2.tar.gz/libde265/fallback-motion.h -> libde265-1.1.3.tar.gz/libde265/fallback-motion.h
Changed
@@ -43,21 +43,29 @@ int width, int height, int w1,int o1, int w2,int o2, int log2WD); +// The 16-bit pixel kernels are templates on the type of the intermediate +// prediction samples (inter_t): int16_t up to MC_MAX_BIT_DEPTH_INT16 (see +// acceleration.h), int32_t above. Instantiated for both types in fallback-motion.cc. + +template <class inter_t> void put_weighted_pred_avg_16_fallback(uint16_t *dst, ptrdiff_t dststride, - const int16_t *src1, const int16_t *src2, + const inter_t *src1, const inter_t *src2, ptrdiff_t srcstride, int width, int height, int bit_depth); +template <class inter_t> void put_unweighted_pred_16_fallback(uint16_t *_dst, ptrdiff_t dststride, - const int16_t *src, ptrdiff_t srcstride, + const inter_t *src, ptrdiff_t srcstride, int width, int height, int bit_depth); +template <class inter_t> void put_weighted_pred_16_fallback(uint16_t *_dst, ptrdiff_t dststride, - const int16_t *src, ptrdiff_t srcstride, + const inter_t *src, ptrdiff_t srcstride, int width, int height, int w,int o,int log2WD, int bit_depth); +template <class inter_t> void put_weighted_bipred_16_fallback(uint16_t *_dst, ptrdiff_t dststride, - const int16_t *src1, const int16_t *src2, ptrdiff_t srcstride, + const inter_t *src1, const inter_t *src2, ptrdiff_t srcstride, int width, int height, int w1,int o1, int w2,int o2, int log2WD, int bit_depth); @@ -68,16 +76,17 @@ int width, int height, int mx, int my, int16_t* mcbuffer); -void put_epel_16_fallback(int16_t *out, ptrdiff_t out_stride, +template <class inter_t> +void put_epel_16_fallback(inter_t *out, ptrdiff_t out_stride, const uint16_t *src, ptrdiff_t src_stride, int width, int height, - int mx, int my, int16_t* mcbuffer, int bit_depth); + int mx, int my, inter_t* mcbuffer, int bit_depth); -template <class pixel_t> -void put_epel_hv_fallback(int16_t *dst, ptrdiff_t dststride, +template <class pixel_t, class inter_t> +void put_epel_hv_fallback(inter_t *dst, ptrdiff_t dststride, const pixel_t *_src, ptrdiff_t srcstride, int width, int height, - int mx, int my, int16_t* mcbuffer, int bit_depth); + int mx, int my, inter_t* mcbuffer, int bit_depth); #define QPEL(x,y) void put_qpel_ ## x ## _ ## y ## _fallback(int16_t *out, ptrdiff_t out_stride, \ @@ -91,14 +100,26 @@ #undef QPEL +template <class inter_t> +void put_qpel_0_0_fallback_16(inter_t *out, ptrdiff_t out_stride, + const uint16_t *src, ptrdiff_t srcstride, + int nPbW, int nPbH, inter_t* mcbuffer, int bit_depth); + #define QPEL(x,y) void put_qpel_ ## x ## _ ## y ## _fallback_16(int16_t *out, ptrdiff_t out_stride, \ const uint16_t *src, ptrdiff_t srcstride, \ int nPbW, int nPbH, int16_t* mcbuffer, int bit_depth) -QPEL(0,0); QPEL(0,1); QPEL(0,2); QPEL(0,3); +/* */ QPEL(0,1); QPEL(0,2); QPEL(0,3); QPEL(1,0); QPEL(1,1); QPEL(1,2); QPEL(1,3); QPEL(2,0); QPEL(2,1); QPEL(2,2); QPEL(2,3); QPEL(3,0); QPEL(3,1); QPEL(3,2); QPEL(3,3); #undef QPEL +// Same with int32_t intermediates (BitDepth > 12), for all fractional +// positions including full-sample (xFracL == yFracL == 0). +void put_qpel_fallback_16_32(int32_t *out, ptrdiff_t out_stride, + const uint16_t *src, ptrdiff_t srcstride, + int nPbW, int nPbH, int32_t* mcbuffer, + int xFracL, int yFracL, int bit_depth); + #endif
View file
libde265-1.1.2.tar.gz/libde265/fallback.cc -> libde265-1.1.3.tar.gz/libde265/fallback.cc
Changed
@@ -32,16 +32,22 @@ accel->put_weighted_pred_8 = put_weighted_pred_8_fallback; accel->put_weighted_bipred_8 = put_weighted_bipred_8_fallback; - accel->put_weighted_pred_avg_16 = put_weighted_pred_avg_16_fallback; - accel->put_unweighted_pred_16 = put_unweighted_pred_16_fallback; - accel->put_weighted_pred_16 = put_weighted_pred_16_fallback; - accel->put_weighted_bipred_16 = put_weighted_bipred_16_fallback; + accel->put_weighted_pred_avg_16 = put_weighted_pred_avg_16_fallback<int16_t>; + accel->put_unweighted_pred_16 = put_unweighted_pred_16_fallback<int16_t>; + accel->put_weighted_pred_16 = put_weighted_pred_16_fallback<int16_t>; + accel->put_weighted_bipred_16 = put_weighted_bipred_16_fallback<int16_t>; + + // BitDepth > 12: int32_t intermediates + accel->put_weighted_pred_avg_16_32 = put_weighted_pred_avg_16_fallback<int32_t>; + accel->put_unweighted_pred_16_32 = put_unweighted_pred_16_fallback<int32_t>; + accel->put_weighted_pred_16_32 = put_weighted_pred_16_fallback<int32_t>; + accel->put_weighted_bipred_16_32 = put_weighted_bipred_16_fallback<int32_t>; accel->put_hevc_epel_8 = put_epel_8_fallback; - accel->put_hevc_epel_h_8 = put_epel_hv_fallback<uint8_t>; - accel->put_hevc_epel_v_8 = put_epel_hv_fallback<uint8_t>; - accel->put_hevc_epel_hv_8 = put_epel_hv_fallback<uint8_t>; + accel->put_hevc_epel_h_8 = put_epel_hv_fallback<uint8_t,int16_t>; + accel->put_hevc_epel_v_8 = put_epel_hv_fallback<uint8_t,int16_t>; + accel->put_hevc_epel_hv_8 = put_epel_hv_fallback<uint8_t,int16_t>; accel->put_hevc_qpel_800 = put_qpel_0_0_fallback; accel->put_hevc_qpel_801 = put_qpel_0_1_fallback; @@ -60,12 +66,12 @@ accel->put_hevc_qpel_832 = put_qpel_3_2_fallback; accel->put_hevc_qpel_833 = put_qpel_3_3_fallback; - accel->put_hevc_epel_16 = put_epel_16_fallback; - accel->put_hevc_epel_h_16 = put_epel_hv_fallback<uint16_t>; - accel->put_hevc_epel_v_16 = put_epel_hv_fallback<uint16_t>; - accel->put_hevc_epel_hv_16 = put_epel_hv_fallback<uint16_t>; + accel->put_hevc_epel_16 = put_epel_16_fallback<int16_t>; + accel->put_hevc_epel_h_16 = put_epel_hv_fallback<uint16_t,int16_t>; + accel->put_hevc_epel_v_16 = put_epel_hv_fallback<uint16_t,int16_t>; + accel->put_hevc_epel_hv_16 = put_epel_hv_fallback<uint16_t,int16_t>; - accel->put_hevc_qpel_1600 = put_qpel_0_0_fallback_16; + accel->put_hevc_qpel_1600 = put_qpel_0_0_fallback_16<int16_t>; accel->put_hevc_qpel_1601 = put_qpel_0_1_fallback_16; accel->put_hevc_qpel_1602 = put_qpel_0_2_fallback_16; accel->put_hevc_qpel_1603 = put_qpel_0_3_fallback_16; @@ -82,6 +88,14 @@ accel->put_hevc_qpel_1632 = put_qpel_3_2_fallback_16; accel->put_hevc_qpel_1633 = put_qpel_3_3_fallback_16; + // BitDepth > 12: int32_t intermediates + accel->put_hevc_epel_16_32 = put_epel_16_fallback<int32_t>; + accel->put_hevc_epel_h_16_32 = put_epel_hv_fallback<uint16_t,int32_t>; + accel->put_hevc_epel_v_16_32 = put_epel_hv_fallback<uint16_t,int32_t>; + accel->put_hevc_epel_hv_16_32 = put_epel_hv_fallback<uint16_t,int32_t>; + + accel->put_hevc_qpel_16_32 = put_qpel_fallback_16_32; + accel->transform_skip_8 = transform_skip_8_fallback;
View file
libde265-1.1.2.tar.gz/libde265/image.cc -> libde265-1.1.3.tar.gz/libde265/image.cc
Changed
@@ -37,6 +37,8 @@ #ifdef HAVE_SSE4_1 // SSE code processes 128bit per iteration and thus might read more data // than is later actually used. +// NOTE: custom image allocators have to provide this padding too. When increasing +// it, update the de265_image_allocation documentation in de265.h accordingly. #define MEMORY_PADDING 16 #else #define MEMORY_PADDING 0 @@ -511,33 +513,26 @@ assert(bytes_per_pixel == 2); // if we fill the same byte value to all bytes, we can still use memset() - memset(pixelschannel, 0, plane_bytes + MEMORY_PADDING); + memset(pixelschannel, value & 0xFF, plane_bytes + MEMORY_PADDING); } else { assert(bytes_per_pixel == 2); uint16_t v = value; - if (channel==0) { - // copy value into first row - for (int x = 0; x < width; x++) { - *reinterpret_cast<uint16_t*>(&pixelschannel2 * x) = v; - } + // Fill whole rows including the stride padding. This covers every byte of the + // plane, so no part of it is left with whatever the image allocator handed us. - // copy first row into remaining rows - for (int y = 1; y < height; y++) { - memcpy(pixelschannel + y * stride * 2, pixelschannel, chroma_width * 2); - } + const ptrdiff_t row_width = (channel==0 ? stride : chroma_stride); + const int nRows = (channel==0 ? height : chroma_height); + + // copy value into first row + for (ptrdiff_t x = 0; x < row_width; x++) { + *reinterpret_cast<uint16_t*>(&pixelschannel2 * x) = v; } - else { - // copy value into first row - for (int x = 0; x < chroma_width; x++) { - *reinterpret_cast<uint16_t*>(&pixelschannel2 * x) = v; - } - // copy first row into remaining rows - for (int y = 1; y < chroma_height; y++) { - memcpy(pixelschannel + y * chroma_stride * 2, pixelschannel, chroma_width * 2); - } + // copy first row into remaining rows + for (int y = 1; y < nRows; y++) { + memcpy(pixelschannel + y * row_width * 2, pixelschannel, row_width * 2); } #if MEMORY_PADDING > 0
View file
libde265-1.1.2.tar.gz/libde265/image.h -> libde265-1.1.3.tar.gz/libde265/image.h
Changed
@@ -88,7 +88,7 @@ MetaDataArray() = default; ~MetaDataArray() { free(data); } - LIBDE265_CHECK_RESULT bool alloc(int w,int h, uint8_t _log2unitSize) { + nodiscard bool alloc(int w,int h, uint8_t _log2unitSize) { int size = w*h; if (size != data_size) {
View file
libde265-1.1.2.tar.gz/libde265/motion.cc -> libde265-1.1.3.tar.gz/libde265/motion.cc
Changed
@@ -45,11 +45,14 @@ -template <class pixel_t> +// Luma sample interpolation process (8.5.3.3.3.2). +// inter_t is the type of the intermediate prediction samples (see +// generate_inter_prediction_samples_plane below). +template <class pixel_t, class inter_t> void mc_luma(const base_context* ctx, const seq_parameter_set* sps, int mv_x, int mv_y, int xP,int yP, - int16_t* out, int out_stride, + inter_t* out, int out_stride, const pixel_t* ref, ptrdiff_t ref_stride, int nPbW, int nPbH, int bitDepth_L) { @@ -59,16 +62,14 @@ int xIntOffsL = xP + (mv_x>>2); int yIntOffsL = yP + (mv_y>>2); - // luma sample interpolation process (8.5.3.2.2.1) - - //const int shift1 = sps->BitDepth_Y-8; + //const int shift1 = std::min(4, sps->BitDepth_Y-8); //const int shift2 = 6; const int shift3 = std::max(2, 14 - sps->BitDepth_Y); int w = sps->pic_width_in_luma_samples; int h = sps->pic_height_in_luma_samples; - ALIGNED_16(int16_t) mcbufferMAX_CU_SIZE * (MAX_CU_SIZE+7); + ALIGNED_16(inter_t) mcbufferMAX_CU_SIZE * (MAX_CU_SIZE+7); if (xFracL==0 && yFracL==0) { @@ -175,18 +176,17 @@ -template <class pixel_t> +// Chroma sample interpolation process (8.5.3.3.3.3). +template <class pixel_t, class inter_t> void mc_chroma(const base_context* ctx, const seq_parameter_set* sps, int mv_x, int mv_y, int xP,int yP, - int16_t* out, int out_stride, + inter_t* out, int out_stride, const pixel_t* ref, ptrdiff_t ref_stride, int nPbWC, int nPbHC, int bit_depth_C) { - // chroma sample interpolation process (8.5.3.2.2.2) - - //const int shift1 = sps->BitDepth_C-8; + //const int shift1 = std::min(4, sps->BitDepth_C-8); //const int shift2 = 6; const int shift3 = std::max(2, 14 - sps->BitDepth_C); @@ -202,7 +202,7 @@ int xIntOffsC = xP/sps->SubWidthC + (mv_x>>3); int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3); - ALIGNED_32(int16_t mcbufferMAX_CU_SIZE*(MAX_CU_SIZE+7)); + ALIGNED_32(inter_t mcbufferMAX_CU_SIZE*(MAX_CU_SIZE+7)); if (xFracC == 0 && yFracC == 0) { if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC && @@ -283,7 +283,160 @@ -// 8.5.3.2 +// Fractional sample interpolation (8.5.3.3.3) and weighted sample prediction +// (8.5.3.3.4) for one colour plane. +// +// inter_t is the type of the intermediate prediction samples predSamplesLX. +// The spec keeps them at max(14, BitDepth+2) bits plus the overshoot of the +// interpolation filters, which fits into int16_t only up to +// MC_MAX_BIT_DEPTH_INT16. Above that, int32_t is used (see acceleration.h). +// +// refPicl is NULL when list l is not used or when its reference picture is +// unusable. The caller has already reported the latter; the prediction is then +// filled with mid-grey. +// +// Forced inline: called once per colour plane from a hot loop, and inlining lets +// the compiler set up the prediction sample buffer once per PB instead of once +// per plane. +template <class inter_t> +static LIBDE265_ALWAYS_INLINE void generate_inter_prediction_samples_plane(base_context* ctx, + const slice_segment_header* shdr, + de265_image* img, + int cIdx, + int xP,int yP, + int nCS, int nPbW,int nPbH, + const PBMotion* vi, + const int predFlag2, + const de265_image* const refPic2) +{ + const pic_parameter_set* pps = shdr->pps.get(); + const seq_parameter_set* sps = pps->sps.get(); + + const int bit_depth = sps->get_bit_depth(cIdx); + + const int SubWidthC = (cIdx==0 ? 1 : sps->SubWidthC); + const int SubHeightC = (cIdx==0 ? 1 : sps->SubHeightC); + const int w = nPbW / SubWidthC; + const int h = nPbH / SubHeightC; + + void* pixels = img->get_image_plane_at_pos_any_depth(cIdx, xP/SubWidthC, yP/SubHeightC); + const ptrdiff_t stride = img->get_image_stride(cIdx); + + // TODO: must predSamples stride really be nCS or can it be something smaller like nPbW? + ALIGNED_16(inter_t) predSamples2 /* LX */MAX_CU_SIZE* MAX_CU_SIZE; + + + // --- fractional sample interpolation (8.5.3.3.3) --- + + for (int l=0;l<2;l++) { + if (!predFlagl) continue; + + if (!refPicl) { + // Fill with mid-grey in intermediate precision: (1 << (bit_depth-1)) << shift3. + const inter_t fill = inter_t(1) << (bit_depth-1 + std::max(2, 14-bit_depth)); + + for (int y=0;y<h;y++) + for (int x=0;x<w;x++) + predSamplesly*nCS+x = fill; + + continue; + } + + if (cIdx==0) { + if (img->high_bit_depth(0)) { + mc_luma(ctx, sps, vi->mvl.x, vi->mvl.y, xP,yP, + predSamplesl,nCS, + (const uint16_t*)refPicl->get_image_plane(0), + refPicl->get_luma_stride(), nPbW,nPbH, bit_depth); + } + else { + mc_luma(ctx, sps, vi->mvl.x, vi->mvl.y, xP,yP, + predSamplesl,nCS, + (const uint8_t*)refPicl->get_image_plane(0), + refPicl->get_luma_stride(), nPbW,nPbH, bit_depth); + } + } + else { + if (img->high_bit_depth(cIdx)) { + mc_chroma(ctx, sps, vi->mvl.x, vi->mvl.y, xP,yP, + predSamplesl,nCS, + (const uint16_t*)refPicl->get_image_plane(cIdx), + refPicl->get_chroma_stride(), w,h, bit_depth); + } + else { + mc_chroma(ctx, sps, vi->mvl.x, vi->mvl.y, xP,yP, + predSamplesl,nCS, + (const uint8_t*)refPicl->get_image_plane(cIdx), + refPicl->get_chroma_stride(), w,h, bit_depth); + } + } + } + + + // --- weighted sample prediction (8.5.3.3.4) --- + + const bool weightedPredFlag = (shdr->slice_type == SLICE_TYPE_P ? + pps->weighted_pred_flag : pps->weighted_bipred_flag); + + // explicit weighted prediction parameters (8.5.3.3.4.3) + + const int shift1 = std::max(2, 14-bit_depth); + const int log2WD = (cIdx==0 ? shdr->luma_log2_weight_denom : shdr->ChromaLog2WeightDenom) + shift1; + const int offsetShift = (cIdx==0 ? sps->WpOffsetBdShiftY : sps->WpOffsetBdShiftC); + + auto weight = &(int l) -> int { + const int refIdx = vi->refIdxl; + return (cIdx==0 ? shdr->LumaWeightlrefIdx : shdr->ChromaWeightlrefIdxcIdx-1); + }; + + auto offset = &(int l) -> int { + const int refIdx = vi->refIdxl; + const int o = (cIdx==0 ? shdr->luma_offsetlrefIdx : shdr->ChromaOffsetlrefIdxcIdx-1); + return o * (1<<offsetShift); + }; + + + if (predFlag0 && predFlag1) { + if (!weightedPredFlag) { + ctx->acceleration.put_weighted_pred_avg(pixels, stride, + predSamples0, predSamples1, nCS, + w,h, bit_depth); + } + else { + logtrace(LogMotion,"weighted-BI-0 %d %d %d %d %dx%d\n", vi->refIdx0, log2WD-6,weight(0),offset(0),w,h); + logtrace(LogMotion,"weighted-BI-1 %d %d %d %d %dx%d\n", vi->refIdx1, log2WD-6,weight(1),offset(1),w,h); + + ctx->acceleration.put_weighted_bipred(pixels, stride, + predSamples0, predSamples1, nCS, + w,h, + weight(0),offset(0),
View file
libde265-1.1.2.tar.gz/libde265/nal-parser.cc -> libde265-1.1.3.tar.gz/libde265/nal-parser.cc
Changed
@@ -26,35 +26,19 @@ #include <stdio.h> #include <stdint.h> #include <limits.h> +#include <utility> #ifdef HAVE_CONFIG_H #include "config.h" #endif -NAL_unit::NAL_unit() - : skipped_bytes(DE265_SKIPPED_BYTES_INITIAL_SIZE) -{ -} - NAL_unit::~NAL_unit() { free(nal_data); } -void NAL_unit::clear() -{ - header = nal_header(); - pts = 0; - user_data = nullptr; - - // set size to zero but keep memory - data_size = 0; - - skipped_bytes.clear(); -} - -LIBDE265_CHECK_RESULT bool NAL_unit::resize(int new_size) +nodiscard bool NAL_unit::resize(int new_size) { if (capacity < new_size) { // Grow the buffer geometrically (1.5x) rather than to the exact requested @@ -87,7 +71,7 @@ return true; } -LIBDE265_CHECK_RESULT bool NAL_unit::append(const unsigned char* in_data, int n) +nodiscard bool NAL_unit::append(const unsigned char* in_data, int n) { if (!resize(data_size + n)) { return false; @@ -99,7 +83,7 @@ return true; } -bool LIBDE265_CHECK_RESULT NAL_unit::set_data(const unsigned char* in_data, int n) +nodiscard bool NAL_unit::set_data(const unsigned char* in_data, int n) { if (!resize(n)) { return false; @@ -174,73 +158,39 @@ NAL_Parser::~NAL_Parser() { - // --- free NAL queues --- - - // empty NAL queue - - NAL_unit* nal; - while ( (nal = pop_from_NAL_queue()) ) { - free_NAL_unit(nal); - } - - // free the pending input NAL - - if (pending_input_NAL != nullptr) { - free_NAL_unit(pending_input_NAL); - } - - // free all NALs in free-list - - for (size_t i=0;i<NAL_free_list.size();i++) { - delete NAL_free_listi; - } + // The NAL queue and the pending input NAL hold owning unique_ptrs, so their + // contents are released automatically. Nothing to do. } -LIBDE265_CHECK_RESULT NAL_unit* NAL_Parser::alloc_NAL_unit(int size) +nodiscard std::unique_ptr<NAL_unit> NAL_Parser::alloc_NAL_unit(int size) { - NAL_unit* nal; - - // --- get NAL-unit object --- + // A freshly constructed NAL_unit is already in the cleared state (empty + // buffer, empty skipped-byte list), so no clear() is needed here. + auto nal = std::make_unique<NAL_unit>(); - if (NAL_free_list.size() > 0) { - nal = NAL_free_list.back(); - NAL_free_list.pop_back(); - } - else { - nal = new NAL_unit; - } - - nal->clear(); if (!nal->resize(size)) { - free_NAL_unit(nal); - return nullptr; + return nullptr; // 'nal' is deleted as it goes out of scope } return nal; } -void NAL_Parser::free_NAL_unit(NAL_unit* nal) +void NAL_Parser::free_NAL_unit(std::unique_ptr<NAL_unit> /*nal*/) { - if (nal == nullptr) { - // Allow calling with nullptr just like regular "free()" - return; - } - if (NAL_free_list.size() < DE265_NAL_FREE_LIST_SIZE) { - NAL_free_list.push_back(nal); - } - else { - delete nal; - } + // Releasing a NAL is just destroying it: ownership is moved in by value, so the + // NAL is deleted when the argument goes out of scope here (a moved-from / null + // argument is a harmless no-op). Kept as a named operation so call sites read as + // an explicit release, and because it makes a double release impossible to express. } -NAL_unit* NAL_Parser::pop_from_NAL_queue() +std::unique_ptr<NAL_unit> NAL_Parser::pop_from_NAL_queue() { if (NAL_queue.empty()) { return nullptr; } else { - NAL_unit* nal = NAL_queue.front(); + std::unique_ptr<NAL_unit> nal = std::move(NAL_queue.front()); NAL_queue.pop(); nBytes_in_NAL_queue -= nal->size(); @@ -249,10 +199,10 @@ } } -void NAL_Parser::push_to_NAL_queue(NAL_unit* nal) +void NAL_Parser::push_to_NAL_queue(std::unique_ptr<NAL_unit> nal) { - NAL_queue.push(nal); nBytes_in_NAL_queue += nal->size(); + NAL_queue.push(std::move(nal)); } de265_error NAL_Parser::push_data(const unsigned char* data, int len, @@ -269,7 +219,8 @@ pending_input_NAL->user_data = user_data; } - NAL_unit* nal = pending_input_NAL; // shortcut + // Raw working pointer for byte access; ownership stays in pending_input_NAL. + NAL_unit* nal = pending_input_NAL.get(); // shortcut // Resize output buffer so that complete input would fit. // We add 3, because in the worst case 3 extra bytes are created for an input byte. @@ -341,16 +292,15 @@ // enforce the maximum NAL size: drop an oversized NAL and resync if (!nal_size_within_limit(out - nal->data())) { - free_NAL_unit(pending_input_NAL); - pending_input_NAL = nullptr; + free_NAL_unit(std::move(pending_input_NAL)); input_push_state = 0; return DE265_ERROR_NAL_SIZE_EXCEEDS_SECURITY_LIMIT; } nal->set_size(out - nal->data());; - // push this NAL decoder queue - push_to_NAL_queue(nal); + // push this completed NAL onto the decoder queue (transfers ownership) + push_to_NAL_queue(std::move(pending_input_NAL)); // initialize new, empty NAL unit @@ -361,7 +311,7 @@ } pending_input_NAL->pts = pts; pending_input_NAL->user_data = user_data; - nal = pending_input_NAL; + nal = pending_input_NAL.get(); out = nal->data(); input_push_state=3; @@ -387,8 +337,7 @@ // reaching a start code. The oversized pending NAL is dropped and the parser // resyncs at the next start code. if (!nal_size_within_limit(nal->size())) {
View file
libde265-1.1.2.tar.gz/libde265/nal-parser.h -> libde265-1.1.3.tar.gz/libde265/nal-parser.h
Changed
@@ -29,14 +29,12 @@ #include <vector> #include <queue> - -constexpr int DE265_NAL_FREE_LIST_SIZE = 16; -constexpr int DE265_SKIPPED_BYTES_INITIAL_SIZE = 16; +#include <memory> class NAL_unit { public: - NAL_unit(); + NAL_unit() = default; ~NAL_unit(); nal_header header; @@ -45,13 +43,11 @@ void* user_data = nullptr; - void clear(); - // --- rbsp data --- - LIBDE265_CHECK_RESULT bool resize(int new_size); - LIBDE265_CHECK_RESULT bool append(const unsigned char* data, int n); - LIBDE265_CHECK_RESULT bool set_data(const unsigned char* data, int n); + nodiscard bool resize(int new_size); + nodiscard bool append(const unsigned char* data, int n); + nodiscard bool set_data(const unsigned char* data, int n); int size() const { return data_size; } void set_size(int s) { data_size=s; } @@ -101,7 +97,7 @@ de265_error push_NAL(const unsigned char* data, int len, de265_PTS pts, void* user_data = nullptr); - NAL_unit* pop_from_NAL_queue(); + std::unique_ptr<NAL_unit> pop_from_NAL_queue(); de265_error flush_data(); void mark_end_of_stream() { end_of_stream=true; } void mark_end_of_frame() { end_of_frame=true; } @@ -123,7 +119,11 @@ return NAL_queue.size(); } - void free_NAL_unit(NAL_unit*); + // Release a NAL. Takes ownership by value, so a move transfers the object here + // and leaves the caller holding nullptr; a redundant release therefore passes + // nullptr and is a harmless no-op, which is what makes a double release + // impossible to express. + void free_NAL_unit(std::unique_ptr<NAL_unit> nal); int get_NAL_queue_length() const { return NAL_queue.size(); } @@ -137,17 +137,17 @@ bool end_of_frame = false; // data in pending_input_data is end of frame int input_push_state = 0; - NAL_unit* pending_input_NAL = nullptr; + std::unique_ptr<NAL_unit> pending_input_NAL; const de265_security_limits* m_security_limits = nullptr; // NAL level - std::queue<NAL_unit*> NAL_queue; // enqueued NALs have suffing bytes removed + std::queue<std::unique_ptr<NAL_unit>> NAL_queue; // enqueued NALs have suffing bytes removed int nBytes_in_NAL_queue = 0; // data bytes currently in NAL_queue - void push_to_NAL_queue(NAL_unit*); + void push_to_NAL_queue(std::unique_ptr<NAL_unit>); // Returns true if a NAL unit of the given size is within the configured // security limit (or if no limit is set). @@ -158,11 +158,7 @@ } - // pool of unused NAL memory - - std::vector<NAL_unit*> NAL_free_list; // maximum size: DE265_NAL_FREE_LIST_SIZE - - LIBDE265_CHECK_RESULT NAL_unit* alloc_NAL_unit(int size); + nodiscard std::unique_ptr<NAL_unit> alloc_NAL_unit(int size); };
View file
libde265-1.1.2.tar.gz/libde265/pps.cc -> libde265-1.1.3.tar.gz/libde265/pps.cc
Changed
@@ -55,12 +55,26 @@ if (pps->transform_skip_enabled_flag) { uvlc = br->get_uvlc(); - if (uvlc == UVLC_ERROR || - uvlc > static_cast<uint32_t>(sps->Log2MaxTrafoSize) - 2) { + if (uvlc == UVLC_ERROR) { ctx->add_warning(DE265_WARNING_PPS_HEADER_INVALID, false); return false; } + // The standard requires log2_max_transform_skip_block_size_minus2 <= + // Log2MaxTrafoSize-2, but real-world RExt streams (e.g. the conformance + // stream PERSIST_RPARAM_A_RExt_Sony_2) code a larger value. This field + // only gates whether transform_skip_flag may be present for a TU of a + // given size (log2TrafoSize <= Log2MaxTransformSkipSize); since + // log2TrafoSize can never exceed Log2MaxTrafoSize, clamping to the + // maximum in-range value reproduces the same "always present" decoding + // behavior as any larger out-of-range value, so it is safe to clamp + // instead of rejecting the whole PPS. + uint32_t maxAllowed = static_cast<uint32_t>(sps->Log2MaxTrafoSize) - 2; + if (uvlc > maxAllowed) { + ctx->add_warning(DE265_WARNING_PPS_HEADER_INVALID, false); + uvlc = maxAllowed; + } + log2_max_transform_skip_block_size = uvlc+2; } @@ -522,12 +536,21 @@ } } - // Multilayer extension and the 6 reserved extension bits would carry - // additional payload that we do not parse. Reject the stream. - if (pps_multilayer_extension_flag || pps_extension_6bits) { + // The reserved extension bits could carry a 3D/SCC PPS extension whose + // payload changes base-layer decoding (e.g. SCC palette / adaptive + // colour transform). We do not parse it, so reject the stream. + if (pps_extension_6bits) { ctx->add_warning(DE265_ERROR_NOT_IMPLEMENTED_YET, false); return false; } + + // The multilayer extension only describes enhancement layers appended + // at the end of the PPS RBSP; skipping its payload does not affect + // base-layer decoding or the parsing of subsequent NAL units, so we + // just warn and continue decoding the base layer. + if (pps_multilayer_extension_flag) { + ctx->add_warning(DE265_ERROR_NOT_IMPLEMENTED_YET, false); + } }
View file
libde265-1.1.2.tar.gz/libde265/slice.cc -> libde265-1.1.3.tar.gz/libde265/slice.cc
Changed
@@ -3266,11 +3266,22 @@ c1 = 1; + /* Whether this sub-block codes any escape data, i.e. any coeff_abs_level_remaining. + Only used for cabac_bypass_alignment_enabled_flag (see below). */ + + bool escapeDataPresent = false; + + // --- decode greater-1 flags --- int newLastGreater1ScanPos = -1; int lastGreater1Coefficient = std::min(8, nCoefficients); + + // significant coefficients past the first eight carry no greater-1 flag and are escape coded + if (nCoefficients > 8) { + escapeDataPresent = true; + } for (int c = 0; c < lastGreater1Coefficient; c++) { int greater1_flag = decode_coeff_abs_level_greater1(tctx, cIdx, i, @@ -3289,6 +3300,9 @@ if (newLastGreater1ScanPos == -1) { newLastGreater1ScanPos = c; } + else { + escapeDataPresent = true; + } } else { coeff_has_max_base_levelc = 0; @@ -3309,6 +3323,10 @@ int flag = decode_coeff_abs_level_greater2(tctx, cIdx, lastInvocation_ctxSet); coeff_valuenewLastGreater1ScanPos += flag; coeff_has_max_base_levelnewLastGreater1ScanPos = flag; + + if (flag) { + escapeDataPresent = true; + } } @@ -3335,6 +3353,14 @@ } + /* (9.3.4.3.6) Align the CABAC engine before the bypass-coded sign flags and + remaining levels of a sub-block that carries escape data. No context-coded bin + follows until the end of the sub-block, so aligning once here covers both. */ + + if (sps.range_extension.cabac_bypass_alignment_enabled_flag && escapeDataPresent) { + tctx->cabac_decoder.align_bypass(); + } + for (int n = 0; n < nCoefficients - 1; n++) { coeff_signn = tctx->cabac_decoder.decode_bypass(); logtrace(LogSlice, "sign%d = %d\n", n, coeff_signn);
View file
libde265-1.1.2.tar.gz/libde265/transform.cc -> libde265-1.1.3.tar.gz/libde265/transform.cc
Changed
@@ -245,18 +245,32 @@ { const int BitDepthC = tctx->img->get_sps().BitDepth_C; const int BitDepthY = tctx->img->get_sps().BitDepth_Y; + const int ResScaleVal = tctx->ResScaleVal; + + /* (8.6.6): rxy += ( ResScaleVal * ( ( rYxy << BitDepthC ) >> BitDepthY ) ) >> 3 + Both shifts operate on a signed value, so together they are a single signed rescaling + by (BitDepthC - BitDepthY). It must not be evaluated on an unsigned type: the right + shift would then be logical and turn every negative luma residual into a large + positive value. Shifting left is expressed as a multiplication because shifting a + negative value left is undefined behaviour before C++20. + */ - for (int y=0;y<nT;y++) - for (int x=0;x<nT;x++) { - /* TODO: the most usual case is definitely BitDepthY == BitDepthC, in which case - we could just omit two shifts. The second most common case is probably - BitDepthY>BitDepthC, for which we could also eliminate one shift. The remaining - case is also one shift only. - */ - - residualy*nT+x += (tctx->ResScaleVal * - static_cast<int32_t>((static_cast<uint32_t>(tctx->residual_lumay*nT+x) << BitDepthC ) >> BitDepthY ) ) >> 3; - } + const int shift = BitDepthY - BitDepthC; + + if (shift >= 0) { + for (int y=0;y<nT;y++) + for (int x=0;x<nT;x++) { + residualy*nT+x += (ResScaleVal * (tctx->residual_lumay*nT+x >> shift)) >> 3; + } + } + else { + const int32_t factor = 1 << (-shift); + + for (int y=0;y<nT;y++) + for (int x=0;x<nT;x++) { + residualy*nT+x += (ResScaleVal * (tctx->residual_lumay*nT+x * factor)) >> 3; + } + } }
View file
libde265-1.1.2.tar.gz/libde265/util.h -> libde265-1.1.3.tar.gz/libde265/util.h
Changed
@@ -49,14 +49,6 @@ #define unlikely(x) __builtin_expect(!!(x), 0) #endif -#if defined(__GNUC__) && (__GNUC__ >= 4) -#define LIBDE265_CHECK_RESULT __attribute__ ((warn_unused_result)) -#elif defined(_MSC_VER) && (_MSC_VER >= 1700) -#define LIBDE265_CHECK_RESULT _Check_return_ -#else -#define LIBDE265_CHECK_RESULT -#endif - // Be careful with these alignment instructions. They only specify the alignment within // a struct. But they cannot make sure that the base address of the struct has the same alignment // when it is dynamically allocated. @@ -65,6 +57,16 @@ #define ALIGNED_8( var ) LIBDE265_DECLARE_ALIGNED( var, 8 ) #define ALIGNED_4( var ) LIBDE265_DECLARE_ALIGNED( var, 4 ) +// Force inlining of a function. Used where the compiler's heuristics would +// otherwise leave a large helper as a separate call on a hot path. +#if defined(_MSC_VER) +#define LIBDE265_ALWAYS_INLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) +#define LIBDE265_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +#define LIBDE265_ALWAYS_INLINE inline +#endif + #ifdef _MSC_VER #ifdef _CPPRTTI #define RTTI_ENABLED
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.